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/. */
6 
7 #include "fuzz-tests/tests.h"
8 
9 #include <stdio.h>
10 
11 #include "js/AllocPolicy.h"
12 #include "js/Initialization.h"
13 #include "js/RootingAPI.h"
14 #include "vm/JSContext.h"
15 
16 #ifdef LIBFUZZER
17 #  include "FuzzerDefs.h"
18 #endif
19 
20 using namespace mozilla;
21 
22 JS::PersistentRootedObject gGlobal;
23 JSContext* gCx = nullptr;
24 
getGlobalClass()25 static const JSClass* getGlobalClass() {
26   static const JSClass c = {"global", JSCLASS_GLOBAL_FLAGS,
27                             &JS::DefaultGlobalClassOps};
28   return &c;
29 }
30 
jsfuzz_createGlobal(JSContext * cx,JSPrincipals * principals)31 static JSObject* jsfuzz_createGlobal(JSContext* cx, JSPrincipals* principals) {
32   /* Create the global object. */
33   JS::RealmOptions options;
34   options.creationOptions().setStreamsEnabled(true).setWeakRefsEnabled(
35       JS::WeakRefSpecifier::EnabledWithCleanupSome);
36   return JS_NewGlobalObject(cx, getGlobalClass(), principals,
37                             JS::FireOnNewGlobalHook, options);
38 }
39 
jsfuzz_init(JSContext ** cx,JS::PersistentRootedObject * global)40 static bool jsfuzz_init(JSContext** cx, JS::PersistentRootedObject* global) {
41   *cx = JS_NewContext(8L * 1024 * 1024);
42   if (!*cx) {
43     return false;
44   }
45 
46   const size_t MAX_STACK_SIZE = 500000;
47 
48   JS_SetNativeStackQuota(*cx, MAX_STACK_SIZE);
49 
50   js::UseInternalJobQueues(*cx);
51   if (!JS::InitSelfHostedCode(*cx)) {
52     return false;
53   }
54   global->init(*cx);
55   *global = jsfuzz_createGlobal(*cx, nullptr);
56   if (!*global) {
57     return false;
58   }
59   JS::EnterRealm(*cx, *global);
60   return true;
61 }
62 
jsfuzz_uninit(JSContext * cx)63 static void jsfuzz_uninit(JSContext* cx) {
64   if (cx) {
65     JS::LeaveRealm(cx, nullptr);
66     JS_DestroyContext(cx);
67     cx = nullptr;
68   }
69 }
70 
main(int argc,char * argv[])71 int main(int argc, char* argv[]) {
72   if (!JS_Init()) {
73     fprintf(stderr, "Error: Call to jsfuzz_init() failed\n");
74     return 1;
75   }
76 
77   if (!jsfuzz_init(&gCx, &gGlobal)) {
78     fprintf(stderr, "Error: Call to jsfuzz_init() failed\n");
79     return 1;
80   }
81 
82   const char* fuzzerEnv = getenv("FUZZER");
83   if (!fuzzerEnv) {
84     fprintf(stderr,
85             "Must specify fuzzing target in FUZZER environment variable\n");
86     return 1;
87   }
88 
89   std::string moduleNameStr(getenv("FUZZER"));
90 
91   FuzzerFunctions funcs =
92       FuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr);
93   FuzzerInitFunc initFunc = funcs.first;
94   FuzzerTestingFunc testingFunc = funcs.second;
95   if (initFunc) {
96     int ret = initFunc(&argc, &argv);
97     if (ret) {
98       fprintf(stderr, "Fuzzing Interface: Error: Initialize callback failed\n");
99       return ret;
100     }
101   }
102 
103   if (!testingFunc) {
104     fprintf(stderr, "Fuzzing Interface: Error: No testing callback found\n");
105     return 1;
106   }
107 
108 #ifdef LIBFUZZER
109   fuzzer::FuzzerDriver(&argc, &argv, testingFunc);
110 #elif __AFL_COMPILER
111   testingFunc(nullptr, 0);
112 #endif
113 
114   jsfuzz_uninit(gCx);
115 
116   JS_ShutDown();
117 
118   return 0;
119 }
120