Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / tools / fuzzing / nyx / Nyx.cpp
blob3fbb520b11ebd945e99bab4a9bd1b67141ea4a89
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Assertions.h"
8 #include "mozilla/Unused.h"
9 #include "mozilla/Vector.h"
10 #include "mozilla/fuzzing/Nyx.h"
11 #include "prinrval.h"
12 #include "prthread.h"
14 #include <algorithm>
15 #include <fstream>
17 #include <unistd.h>
19 namespace mozilla {
20 namespace fuzzing {
22 Nyx::Nyx() {
23 char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE");
24 if (testFilePtr) {
25 mReplayMode = true;
29 // static
30 Nyx& Nyx::instance() {
31 static Nyx nyx;
32 return nyx;
35 extern "C" {
36 MOZ_EXPORT __attribute__((weak)) void nyx_start(void);
37 MOZ_EXPORT __attribute__((weak)) uint32_t nyx_get_next_fuzz_data(void*,
38 uint32_t);
39 MOZ_EXPORT __attribute__((weak)) uint32_t nyx_get_raw_fuzz_data(void*,
40 uint32_t);
41 MOZ_EXPORT __attribute__((weak)) void nyx_release(uint32_t);
42 MOZ_EXPORT __attribute__((weak)) void nyx_handle_event(const char*, const char*,
43 int, const char*);
44 MOZ_EXPORT __attribute__((weak)) void nyx_puts(const char*);
45 MOZ_EXPORT __attribute__((weak)) void nyx_dump_file(void* buffer, size_t len,
46 const char* filename);
50 * In this macro, we must avoid calling MOZ_CRASH and friends, as these
51 * calls will redirect to the Nyx event handler routines. If the library
52 * is not properly preloaded, we will crash in the process. Instead, emit
53 * a descriptive error and then force a crash that won't be redirected.
55 #define NYX_CHECK_API(func) \
56 if (!func) { \
57 fprintf( \
58 stderr, \
59 "Error: Nyx library must be in LD_PRELOAD. Missing function \"%s\"\n", \
60 #func); \
61 MOZ_REALLY_CRASH(__LINE__); \
64 void Nyx::start(void) {
65 MOZ_RELEASE_ASSERT(!mInited);
66 mInited = true;
68 // Check if we are in replay mode.
69 char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE");
70 if (testFilePtr) {
71 MOZ_FUZZING_NYX_PRINT("[Replay Mode] Reading data file...\n");
73 std::string testFile(testFilePtr);
74 std::ifstream is;
75 is.open(testFile, std::ios::binary);
77 // The data chunks we receive through Nyx are stored in the data
78 // section of the testfile as chunks prefixed with a 16-bit data
79 // length that we mask down to 11-bit. We read all chunks and
80 // store them away to simulate how we originally received the data
81 // via Nyx.
83 if (is.good()) {
84 mRawReplayBuffer = new Vector<uint8_t>();
85 is.seekg(0, is.end);
86 int rawLength = is.tellg();
87 mozilla::Unused << mRawReplayBuffer->initLengthUninitialized(rawLength);
88 is.seekg(0, is.beg);
89 is.read(reinterpret_cast<char*>(mRawReplayBuffer->begin()), rawLength);
90 is.seekg(0, is.beg);
93 while (is.good()) {
94 uint16_t pktsize;
95 is.read(reinterpret_cast<char*>(&pktsize), sizeof(uint16_t));
97 pktsize &= 0x7ff;
99 if (!is.good()) {
100 break;
103 auto buffer = new Vector<uint8_t>();
105 mozilla::Unused << buffer->initLengthUninitialized(pktsize);
106 is.read(reinterpret_cast<char*>(buffer->begin()), buffer->length());
108 MOZ_FUZZING_NYX_PRINTF("[Replay Mode] Read data packet of size %zu\n",
109 buffer->length());
111 mReplayBuffers.push_back(buffer);
114 if (!mReplayBuffers.size()) {
115 MOZ_FUZZING_NYX_PRINT("[Replay Mode] Error: No buffers read.\n");
116 _exit(1);
119 is.close();
121 if (!!getenv("MOZ_FUZZ_WAIT_BEFORE_REPLAY")) {
122 // This can be useful in some cases to reproduce intermittent issues.
123 PR_Sleep(PR_MillisecondsToInterval(5000));
126 return;
129 NYX_CHECK_API(nyx_start);
130 NYX_CHECK_API(nyx_get_next_fuzz_data);
131 NYX_CHECK_API(nyx_get_raw_fuzz_data);
132 NYX_CHECK_API(nyx_release);
133 NYX_CHECK_API(nyx_handle_event);
134 NYX_CHECK_API(nyx_puts);
135 NYX_CHECK_API(nyx_dump_file);
137 nyx_start();
140 bool Nyx::started(void) { return mInited; }
142 bool Nyx::is_enabled(const char* identifier) {
143 static char* fuzzer = getenv("NYX_FUZZER");
144 if (!fuzzer || strcmp(fuzzer, identifier)) {
145 return false;
147 return true;
150 bool Nyx::is_replay() { return mReplayMode; }
152 uint32_t Nyx::get_data(uint8_t* data, uint32_t size) {
153 MOZ_RELEASE_ASSERT(mInited);
155 if (mReplayMode) {
156 if (!mReplayBuffers.size()) {
157 return 0xFFFFFFFF;
160 Vector<uint8_t>* buffer = mReplayBuffers.front();
161 mReplayBuffers.pop_front();
163 size = std::min(size, (uint32_t)buffer->length());
164 memcpy(data, buffer->begin(), size);
166 delete buffer;
168 return size;
171 return nyx_get_next_fuzz_data(data, size);
174 uint32_t Nyx::get_raw_data(uint8_t* data, uint32_t size) {
175 MOZ_RELEASE_ASSERT(mInited);
177 if (mReplayMode) {
178 size = std::min(size, (uint32_t)mRawReplayBuffer->length());
179 memcpy(data, mRawReplayBuffer->begin(), size);
180 return size;
183 return nyx_get_raw_fuzz_data(data, size);
186 void Nyx::release(uint32_t iterations) {
187 MOZ_RELEASE_ASSERT(mInited);
189 if (mReplayMode) {
190 MOZ_FUZZING_NYX_PRINT("[Replay Mode] Nyx::release() called.\n");
192 // If we reach this point in replay mode, we are essentially done.
193 // Let's wait a bit further for things to settle and then exit.
194 PR_Sleep(PR_MillisecondsToInterval(5000));
195 _exit(1);
198 MOZ_FUZZING_NYX_DEBUG("[DEBUG] Nyx::release() called.\n");
200 nyx_release(iterations);
203 void Nyx::handle_event(const char* type, const char* file, int line,
204 const char* reason) {
205 if (mReplayMode) {
206 MOZ_FUZZING_NYX_PRINTF(
207 "[Replay Mode] Nyx::handle_event() called: %s at %s:%d : %s\n", type,
208 file, line, reason);
209 return;
212 if (mInited) {
213 nyx_handle_event(type, file, line, reason);
214 } else {
215 // We can have events such as MOZ_CRASH even before we snapshot.
216 // Output some useful information to make it clear where it happened.
217 MOZ_FUZZING_NYX_PRINTF(
218 "[ERROR] PRE SNAPSHOT Nyx::handle_event() called: %s at %s:%d : %s\n",
219 type, file, line, reason);
223 void Nyx::dump_file(void* buffer, size_t len, const char* filename) {
224 if (!mReplayMode) {
225 nyx_dump_file(buffer, len, filename);
229 } // namespace fuzzing
230 } // namespace mozilla