fuzz_bytecode.c (4693B)
1 // Copyright 2025 Google LLC 2 // Fuzz target for QuickJS bytecode execution 3 4 #include "quickjs.h" 5 #include "quickjs-libc.h" 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <stdio.h> 10 11 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 12 if (size < 8) return 0; // Need at least minimal bytecode header 13 14 JSRuntime* rt = JS_NewRuntime(); 15 if (!rt) return 0; 16 17 JSContext* ctx = JS_NewContext(rt); 18 if (!ctx) { 19 JS_FreeRuntime(rt); 20 return 0; 21 } 22 23 char load_script[256]; 24 snprintf(load_script, sizeof(load_script), 25 "(function() { " 26 " var buf = new Uint8Array(%zu); " 27 " for (var i = 0; i < %zu; i++) buf[i] = 0; " 28 " return evalBinary(buf); " 29 "})()", size, size); 30 31 JSValue eval_result = JS_Eval(ctx, load_script, strlen(load_script), 32 "<bytecode-load>", 0); 33 34 if (!JS_IsException(eval_result)) { 35 JS_FreeValue(ctx, eval_result); 36 } else { 37 JS_GetException(ctx); 38 } 39 40 const char* simple_script = "({ a: 1, b: 'test', c: function() { return 42; } })"; 41 42 JSValue bytecode = JS_Eval(ctx, simple_script, strlen(simple_script), 43 "<compile>", JS_EVAL_FLAG_COMPILE_ONLY); 44 45 if (!JS_IsException(bytecode)) { 46 size_t bytecode_len; 47 uint8_t* bytecode_buf = JS_WriteObject(ctx, &bytecode_len, bytecode, 48 JS_WRITE_OBJ_BYTECODE); 49 50 if (bytecode_buf) { 51 JSValue loaded = JS_ReadObject(ctx, bytecode_buf, bytecode_len, 52 JS_READ_OBJ_BYTECODE); 53 54 if (!JS_IsException(loaded)) { 55 JSValue result = JS_EvalFunction(ctx, loaded); 56 if (!JS_IsException(result)) { 57 JS_FreeValue(ctx, result); 58 } else { 59 JS_GetException(ctx); 60 } 61 } else { 62 JS_GetException(ctx); 63 } 64 65 js_free(ctx, bytecode_buf); 66 } 67 68 JS_FreeValue(ctx, bytecode); 69 } else { 70 JS_GetException(ctx); 71 } 72 73 if (size >= 8) { 74 uint8_t* fake_bytecode = malloc(size); 75 if (fake_bytecode) { 76 memcpy(fake_bytecode, data, size); 77 78 if (data[0] % 2 == 0) { 79 fake_bytecode[0] = 'Q'; 80 fake_bytecode[1] = 'C'; 81 fake_bytecode[2] = 'A'; 82 fake_bytecode[3] = 'M'; 83 } 84 85 JSValue malformed = JS_ReadObject(ctx, fake_bytecode, size, 86 JS_READ_OBJ_BYTECODE); 87 if (!JS_IsException(malformed)) { 88 JS_FreeValue(ctx, malformed); 89 } else { 90 JS_GetException(ctx); 91 } 92 93 free(fake_bytecode); 94 } 95 } 96 97 const char* eval_script_test = "typeof std !== 'undefined' ? std.evalScript : null"; 98 JSValue std_check = JS_Eval(ctx, eval_script_test, strlen(eval_script_test), 99 "<std-check>", 0); 100 if (!JS_IsException(std_check)) { 101 JS_FreeValue(ctx, std_check); 102 } else { 103 JS_GetException(ctx); 104 } 105 106 const char* module_script = "export default 42; export const x = 123;"; 107 JSValue module_bytecode = JS_Eval(ctx, module_script, strlen(module_script), 108 "<module-compile>", 109 JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 110 111 if (!JS_IsException(module_bytecode)) { 112 size_t mod_bc_len; 113 uint8_t* mod_bc_buf = JS_WriteObject(ctx, &mod_bc_len, module_bytecode, 114 JS_WRITE_OBJ_BYTECODE); 115 116 if (mod_bc_buf) { 117 JSValue mod_loaded = JS_ReadObject(ctx, mod_bc_buf, mod_bc_len, 118 JS_READ_OBJ_BYTECODE); 119 if (!JS_IsException(mod_loaded)) { 120 JSValue mod_result = JS_EvalFunction(ctx, mod_loaded); 121 if (!JS_IsException(mod_result)) { 122 JS_FreeValue(ctx, mod_result); 123 } else { 124 JS_GetException(ctx); 125 } 126 } else { 127 JS_GetException(ctx); 128 } 129 130 js_free(ctx, mod_bc_buf); 131 } 132 133 JS_FreeValue(ctx, module_bytecode); 134 } else { 135 JS_GetException(ctx); 136 } 137 138 JS_FreeContext(ctx); 139 JS_FreeRuntime(rt); 140 141 return 0; 142 }