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"
23 char* testFilePtr
= getenv("MOZ_FUZZ_TESTFILE");
30 Nyx
& Nyx::instance() {
36 MOZ_EXPORT
__attribute__((weak
)) void nyx_start(void);
37 MOZ_EXPORT
__attribute__((weak
)) uint32_t nyx_get_next_fuzz_data(void*,
39 MOZ_EXPORT
__attribute__((weak
)) uint32_t nyx_get_raw_fuzz_data(void*,
41 MOZ_EXPORT
__attribute__((weak
)) void nyx_release(uint32_t);
42 MOZ_EXPORT
__attribute__((weak
)) void nyx_handle_event(const char*, 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) \
59 "Error: Nyx library must be in LD_PRELOAD. Missing function \"%s\"\n", \
61 MOZ_REALLY_CRASH(__LINE__); \
64 void Nyx::start(void) {
65 MOZ_RELEASE_ASSERT(!mInited
);
68 // Check if we are in replay mode.
69 char* testFilePtr
= getenv("MOZ_FUZZ_TESTFILE");
71 MOZ_FUZZING_NYX_PRINT("[Replay Mode] Reading data file...\n");
73 std::string
testFile(testFilePtr
);
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
84 mRawReplayBuffer
= new Vector
<uint8_t>();
86 int rawLength
= is
.tellg();
87 mozilla::Unused
<< mRawReplayBuffer
->initLengthUninitialized(rawLength
);
89 is
.read(reinterpret_cast<char*>(mRawReplayBuffer
->begin()), rawLength
);
95 is
.read(reinterpret_cast<char*>(&pktsize
), sizeof(uint16_t));
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",
111 mReplayBuffers
.push_back(buffer
);
114 if (!mReplayBuffers
.size()) {
115 MOZ_FUZZING_NYX_PRINT("[Replay Mode] Error: No buffers read.\n");
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));
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
);
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
)) {
150 bool Nyx::is_replay() { return mReplayMode
; }
152 uint32_t Nyx::get_data(uint8_t* data
, uint32_t size
) {
153 MOZ_RELEASE_ASSERT(mInited
);
156 if (!mReplayBuffers
.size()) {
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
);
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
);
178 size
= std::min(size
, (uint32_t)mRawReplayBuffer
->length());
179 memcpy(data
, mRawReplayBuffer
->begin(), size
);
183 return nyx_get_raw_fuzz_data(data
, size
);
186 void Nyx::release(uint32_t iterations
) {
187 MOZ_RELEASE_ASSERT(mInited
);
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));
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
) {
206 MOZ_FUZZING_NYX_PRINTF(
207 "[Replay Mode] Nyx::handle_event() called: %s at %s:%d : %s\n", type
,
213 nyx_handle_event(type
, file
, line
, reason
);
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
) {
225 nyx_dump_file(buffer
, len
, filename
);
229 } // namespace fuzzing
230 } // namespace mozilla