1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * * This Source Code Form is subject to the terms of the Mozilla Public
3 * * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include <cstdlib>
7
8 #include "FuzzerRunner.h"
9 #include "mozilla/Attributes.h"
10 #include "prenv.h"
11
12 #include "FuzzerTestHarness.h"
13
14 namespace mozilla {
15
16 // We use a static var 'fuzzerRunner' defined in nsAppRunner.cpp.
17 // fuzzerRunner is initialized to nullptr but if this file is linked in,
18 // then fuzzerRunner will be set here indicating that
19 // we want to call into either LibFuzzer's main or the AFL entrypoint.
20 class _InitFuzzer {
21 public:
_InitFuzzer()22 _InitFuzzer() { fuzzerRunner = new FuzzerRunner(); }
InitXPCOM()23 void InitXPCOM() { mScopedXPCOM = new ScopedXPCOM("Fuzzer"); }
DeinitXPCOM()24 void DeinitXPCOM() {
25 if (mScopedXPCOM) delete mScopedXPCOM;
26 mScopedXPCOM = nullptr;
27 }
28
29 private:
30 ScopedXPCOM* mScopedXPCOM;
31 } InitLibFuzzer;
32
DeinitXPCOM()33 static void DeinitXPCOM() { InitLibFuzzer.DeinitXPCOM(); }
34
Run(int * argc,char *** argv)35 int FuzzerRunner::Run(int* argc, char*** argv) {
36 /*
37 * libFuzzer uses exit() calls in several places instead of returning,
38 * so the destructor of ScopedXPCOM is not called in some cases.
39 * For fuzzing, this does not make a difference, but in debug builds
40 * when running a single testcase, this causes an assertion when destroying
41 * global linked lists. For this reason, we allocate ScopedXPCOM on the heap
42 * using the global InitLibFuzzer class, combined with an atexit call to
43 * destroy the ScopedXPCOM instance again.
44 */
45 InitLibFuzzer.InitXPCOM();
46 std::atexit(DeinitXPCOM);
47
48 const char* fuzzerEnv = getenv("FUZZER");
49
50 if (!fuzzerEnv) {
51 fprintf(stderr,
52 "Must specify fuzzing target in FUZZER environment variable\n");
53 exit(1);
54 }
55
56 std::string moduleNameStr(fuzzerEnv);
57 FuzzerFunctions funcs =
58 FuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr);
59 FuzzerInitFunc initFunc = funcs.first;
60 FuzzerTestingFunc testingFunc = funcs.second;
61 if (initFunc) {
62 int ret = initFunc(argc, argv);
63 if (ret) {
64 fprintf(stderr, "Fuzzing Interface: Error: Initialize callback failed\n");
65 exit(1);
66 }
67 }
68
69 if (!testingFunc) {
70 fprintf(stderr, "Fuzzing Interface: Error: No testing callback found\n");
71 exit(1);
72 }
73
74 #ifdef LIBFUZZER
75 int ret = mFuzzerDriver(argc, argv, testingFunc);
76 #else
77 // For AFL, testingFunc points to the entry function we need.
78 int ret = testingFunc(NULL, 0);
79 #endif
80
81 InitLibFuzzer.DeinitXPCOM();
82 return ret;
83 }
84
85 #ifdef LIBFUZZER
setParams(LibFuzzerDriver aDriver)86 void FuzzerRunner::setParams(LibFuzzerDriver aDriver) {
87 mFuzzerDriver = aDriver;
88 }
89 #endif
90
91 } // namespace mozilla
92