quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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 }