mirror of
https://github.com/bellard/quickjs.git
synced 2026-06-07 06:32:08 +00:00
Add fuzz targets for ES6 modules, JSON, RegExp, and bytecode (#512)
* Add fuzz targets for ES6 modules, JSON, RegExp, and bytecode Adds 4 new fuzzers targeting high-complexity, low-coverage functions: - fuzz_module_export: Tests ES6 module export/import parsing (complexity 6727) - fuzz_json: Tests JSON stringify/parse (complexity ~5000) - fuzz_regexp_compile: Tests RegExp compilation (complexity 5528) - fuzz_bytecode: Tests bytecode execution (complexity 5383) Identified by Fuzz Introspector as having 0% runtime coverage. Build integration for fuzz/Makefile and build.sh included. * Convert fuzz targets from C++ to C and use standard C headers
This commit is contained in:
parent
cfc846a31c
commit
8b045501f9
142
fuzz/fuzz_bytecode.c
Normal file
142
fuzz/fuzz_bytecode.c
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Fuzz target for QuickJS bytecode execution
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 8) return 0; // Need at least minimal bytecode header
|
||||
|
||||
JSRuntime* rt = JS_NewRuntime();
|
||||
if (!rt) return 0;
|
||||
|
||||
JSContext* ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char load_script[256];
|
||||
snprintf(load_script, sizeof(load_script),
|
||||
"(function() { "
|
||||
" var buf = new Uint8Array(%zu); "
|
||||
" for (var i = 0; i < %zu; i++) buf[i] = 0; "
|
||||
" return evalBinary(buf); "
|
||||
"})()", size, size);
|
||||
|
||||
JSValue eval_result = JS_Eval(ctx, load_script, strlen(load_script),
|
||||
"<bytecode-load>", 0);
|
||||
|
||||
if (!JS_IsException(eval_result)) {
|
||||
JS_FreeValue(ctx, eval_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* simple_script = "({ a: 1, b: 'test', c: function() { return 42; } })";
|
||||
|
||||
JSValue bytecode = JS_Eval(ctx, simple_script, strlen(simple_script),
|
||||
"<compile>", JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
|
||||
if (!JS_IsException(bytecode)) {
|
||||
size_t bytecode_len;
|
||||
uint8_t* bytecode_buf = JS_WriteObject(ctx, &bytecode_len, bytecode,
|
||||
JS_WRITE_OBJ_BYTECODE);
|
||||
|
||||
if (bytecode_buf) {
|
||||
JSValue loaded = JS_ReadObject(ctx, bytecode_buf, bytecode_len,
|
||||
JS_READ_OBJ_BYTECODE);
|
||||
|
||||
if (!JS_IsException(loaded)) {
|
||||
JSValue result = JS_EvalFunction(ctx, loaded);
|
||||
if (!JS_IsException(result)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
js_free(ctx, bytecode_buf);
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, bytecode);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
if (size >= 8) {
|
||||
uint8_t* fake_bytecode = malloc(size);
|
||||
if (fake_bytecode) {
|
||||
memcpy(fake_bytecode, data, size);
|
||||
|
||||
if (data[0] % 2 == 0) {
|
||||
fake_bytecode[0] = 'Q';
|
||||
fake_bytecode[1] = 'C';
|
||||
fake_bytecode[2] = 'A';
|
||||
fake_bytecode[3] = 'M';
|
||||
}
|
||||
|
||||
JSValue malformed = JS_ReadObject(ctx, fake_bytecode, size,
|
||||
JS_READ_OBJ_BYTECODE);
|
||||
if (!JS_IsException(malformed)) {
|
||||
JS_FreeValue(ctx, malformed);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
free(fake_bytecode);
|
||||
}
|
||||
}
|
||||
|
||||
const char* eval_script_test = "typeof std !== 'undefined' ? std.evalScript : null";
|
||||
JSValue std_check = JS_Eval(ctx, eval_script_test, strlen(eval_script_test),
|
||||
"<std-check>", 0);
|
||||
if (!JS_IsException(std_check)) {
|
||||
JS_FreeValue(ctx, std_check);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* module_script = "export default 42; export const x = 123;";
|
||||
JSValue module_bytecode = JS_Eval(ctx, module_script, strlen(module_script),
|
||||
"<module-compile>",
|
||||
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
|
||||
if (!JS_IsException(module_bytecode)) {
|
||||
size_t mod_bc_len;
|
||||
uint8_t* mod_bc_buf = JS_WriteObject(ctx, &mod_bc_len, module_bytecode,
|
||||
JS_WRITE_OBJ_BYTECODE);
|
||||
|
||||
if (mod_bc_buf) {
|
||||
JSValue mod_loaded = JS_ReadObject(ctx, mod_bc_buf, mod_bc_len,
|
||||
JS_READ_OBJ_BYTECODE);
|
||||
if (!JS_IsException(mod_loaded)) {
|
||||
JSValue mod_result = JS_EvalFunction(ctx, mod_loaded);
|
||||
if (!JS_IsException(mod_result)) {
|
||||
JS_FreeValue(ctx, mod_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
js_free(ctx, mod_bc_buf);
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, module_bytecode);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
131
fuzz/fuzz_json.c
Normal file
131
fuzz/fuzz_json.c
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Fuzz target for QuickJS JSON operations
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 1) return 0;
|
||||
|
||||
JSRuntime* rt = JS_NewRuntime();
|
||||
if (!rt) return 0;
|
||||
|
||||
JSContext* ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* input = malloc(size + 1);
|
||||
if (!input) {
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
memcpy(input, data, size);
|
||||
input[size] = '\0';
|
||||
|
||||
char parse_script[8192];
|
||||
snprintf(parse_script, sizeof(parse_script),
|
||||
"JSON.parse(JSON.stringify(%s))", input);
|
||||
|
||||
JSValue parse_result = JS_Eval(ctx, parse_script, strlen(parse_script),
|
||||
"<json-fuzz>", 0);
|
||||
|
||||
if (JS_IsException(parse_result)) {
|
||||
JS_GetException(ctx);
|
||||
} else {
|
||||
JS_FreeValue(ctx, parse_result);
|
||||
}
|
||||
|
||||
char direct_parse[16384];
|
||||
snprintf(direct_parse, sizeof(direct_parse), "JSON.parse('");
|
||||
|
||||
size_t script_len = strlen(direct_parse);
|
||||
for (size_t i = 0; i < size && script_len < sizeof(direct_parse) - 20; i++) {
|
||||
char c = input[i];
|
||||
if (c == '\\' || c == '\'') {
|
||||
direct_parse[script_len++] = '\\';
|
||||
}
|
||||
if (c >= 32 && c < 127) {
|
||||
direct_parse[script_len++] = c;
|
||||
}
|
||||
}
|
||||
strcat(direct_parse + script_len, "');");
|
||||
|
||||
JSValue direct_result = JS_Eval(ctx, direct_parse, strlen(direct_parse),
|
||||
"<json-direct>", 0);
|
||||
if (JS_IsException(direct_result)) {
|
||||
JS_GetException(ctx);
|
||||
} else {
|
||||
JS_FreeValue(ctx, direct_result);
|
||||
}
|
||||
|
||||
char stringify_script[8192];
|
||||
snprintf(stringify_script, sizeof(stringify_script),
|
||||
"var obj = { data: %s, num: 123, str: 'test', bool: true, nullv: null, "
|
||||
"arr: [1,2,3], nested: { a: 1 } }; JSON.stringify(obj);",
|
||||
input);
|
||||
|
||||
JSValue stringify_result = JS_Eval(ctx, stringify_script,
|
||||
strlen(stringify_script), "<json-stringify>", 0);
|
||||
if (JS_IsException(stringify_result)) {
|
||||
JS_GetException(ctx);
|
||||
} else {
|
||||
const char* str = JS_ToCString(ctx, stringify_result);
|
||||
if (str) {
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
JS_FreeValue(ctx, stringify_result);
|
||||
}
|
||||
|
||||
const char* spacing_tests[] = {
|
||||
"JSON.stringify({a:1,b:2})",
|
||||
"JSON.stringify({a:1,b:2}, null, 2)",
|
||||
"JSON.stringify({a:1,b:2}, null, ' ')",
|
||||
"JSON.stringify([1,2,3])",
|
||||
"JSON.stringify(null)",
|
||||
"JSON.stringify(undefined)",
|
||||
"JSON.stringify(123)",
|
||||
"JSON.stringify('string')",
|
||||
"JSON.stringify(true)",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(spacing_tests) / sizeof(spacing_tests[0]); i++) {
|
||||
JSValue r = JS_Eval(ctx, spacing_tests[i], strlen(spacing_tests[i]),
|
||||
"<json-test>", 0);
|
||||
if (!JS_IsException(r)) {
|
||||
JS_FreeValue(ctx, r);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
const char* reviver_test = "JSON.parse('{\"a\":1,\"b\":2}', function(k,v) { return v; })";
|
||||
JSValue reviver_result = JS_Eval(ctx, reviver_test, strlen(reviver_test),
|
||||
"<json-reviver>", 0);
|
||||
if (!JS_IsException(reviver_result)) {
|
||||
JS_FreeValue(ctx, reviver_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* replacer_test = "JSON.stringify({a:1,b:2}, function(k,v) { return v; })";
|
||||
JSValue replacer_result = JS_Eval(ctx, replacer_test, strlen(replacer_test),
|
||||
"<json-replacer>", 0);
|
||||
if (!JS_IsException(replacer_result)) {
|
||||
JS_FreeValue(ctx, replacer_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
free(input);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
105
fuzz/fuzz_module_export.c
Normal file
105
fuzz/fuzz_module_export.c
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Fuzz target for QuickJS ES6 module parsing
|
||||
|
||||
#include "quickjs.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 1) return 0;
|
||||
|
||||
JSRuntime* rt = JS_NewRuntime();
|
||||
if (!rt) return 0;
|
||||
|
||||
JSContext* ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* input = malloc(size + 1);
|
||||
if (!input) {
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
memcpy(input, data, size);
|
||||
input[size] = '\0';
|
||||
|
||||
const char* export_patterns[] = {
|
||||
"export default %s;",
|
||||
"export const x = %s;",
|
||||
"export let x = %s;",
|
||||
"export var x = %s;",
|
||||
"export function f() { %s }",
|
||||
"export class C { %s }",
|
||||
"export { %s };",
|
||||
"export * from '%s';",
|
||||
"export { %s } from 'module';",
|
||||
"export { default as x } from '%s';",
|
||||
};
|
||||
|
||||
int pattern_idx = data[0] % (sizeof(export_patterns) / sizeof(export_patterns[0]));
|
||||
|
||||
char script[8192];
|
||||
snprintf(script, sizeof(script), export_patterns[pattern_idx], input);
|
||||
|
||||
JSValue result = JS_Eval(ctx, script, strlen(script), "<input>",
|
||||
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
|
||||
if (!JS_IsException(result)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
JSValue result2 = JS_Eval(ctx, input, size, "<input>", JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (!JS_IsException(result2)) {
|
||||
JS_FreeValue(ctx, result2);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* import_patterns[] = {
|
||||
"import '%s';",
|
||||
"import x from '%s';",
|
||||
"import * as x from '%s';",
|
||||
"import { x } from '%s';",
|
||||
"import { x as y } from '%s';",
|
||||
"import x, { y } from '%s';",
|
||||
"import x, * as y from '%s';",
|
||||
};
|
||||
|
||||
int import_idx = (data[0] >> 4) % (sizeof(import_patterns) / sizeof(import_patterns[0]));
|
||||
char import_script[8192];
|
||||
char* sanitized = malloc(size + 1);
|
||||
if (sanitized) {
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < size && j < size; i++) {
|
||||
if (data[i] != '\'' && data[i] != '"' && data[i] != '\n' && data[i] != '\r') {
|
||||
sanitized[j++] = data[i];
|
||||
}
|
||||
}
|
||||
sanitized[j] = '\0';
|
||||
|
||||
snprintf(import_script, sizeof(import_script), import_patterns[import_idx], sanitized);
|
||||
|
||||
JSValue import_result = JS_Eval(ctx, import_script, strlen(import_script), "<input>",
|
||||
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (!JS_IsException(import_result)) {
|
||||
JS_FreeValue(ctx, import_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
free(sanitized);
|
||||
}
|
||||
|
||||
free(input);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
177
fuzz/fuzz_regexp_compile.c
Normal file
177
fuzz/fuzz_regexp_compile.c
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Fuzz target for QuickJS RegExp compilation
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 2) return 0;
|
||||
|
||||
JSRuntime* rt = JS_NewRuntime();
|
||||
if (!rt) return 0;
|
||||
|
||||
JSContext* ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t pattern_len = size / 2;
|
||||
size_t flags_len = size - pattern_len;
|
||||
|
||||
if (pattern_len == 0 || flags_len == 0) {
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* pattern = malloc(pattern_len + 1);
|
||||
char* flags = malloc(flags_len + 1);
|
||||
|
||||
if (!pattern || !flags) {
|
||||
free(pattern);
|
||||
free(flags);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pattern, data, pattern_len);
|
||||
pattern[pattern_len] = '\0';
|
||||
|
||||
memcpy(flags, data + pattern_len, flags_len);
|
||||
flags[flags_len] = '\0';
|
||||
|
||||
char valid_flags[16];
|
||||
size_t valid_idx = 0;
|
||||
const char* valid = "gimsuy";
|
||||
for (size_t i = 0; i < flags_len && valid_idx < sizeof(valid_flags) - 1; i++) {
|
||||
if (strchr(valid, flags[i]) && !strchr(valid_flags, flags[i])) {
|
||||
valid_flags[valid_idx++] = flags[i];
|
||||
}
|
||||
}
|
||||
valid_flags[valid_idx] = '\0';
|
||||
|
||||
char script[8192];
|
||||
char escaped_pattern[4096];
|
||||
size_t esc_idx = 0;
|
||||
for (size_t i = 0; i < pattern_len && esc_idx < sizeof(escaped_pattern) - 2; i++) {
|
||||
if (pattern[i] == '\\' || pattern[i] == '"' || pattern[i] == '\n' ||
|
||||
pattern[i] == '\r' || pattern[i] == '\t') {
|
||||
escaped_pattern[esc_idx++] = '\\';
|
||||
}
|
||||
escaped_pattern[esc_idx++] = pattern[i];
|
||||
}
|
||||
escaped_pattern[esc_idx] = '\0';
|
||||
|
||||
snprintf(script, sizeof(script), "new RegExp(\"%s\", \"%s\")",
|
||||
escaped_pattern, valid_flags);
|
||||
|
||||
JSValue regexp_result = JS_Eval(ctx, script, strlen(script), "<regexp>", 0);
|
||||
|
||||
if (!JS_IsException(regexp_result)) {
|
||||
const char* test_strings[] = {
|
||||
"'test string'",
|
||||
"''",
|
||||
"'aaaaaaaaaa'",
|
||||
"'1234567890'",
|
||||
"'!@#$%^&*()'",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(test_strings) / sizeof(test_strings[0]); i++) {
|
||||
char match_script[4096];
|
||||
snprintf(match_script, sizeof(match_script),
|
||||
"var re = %s; re.test(%s); re.exec(%s); %s.match(re);",
|
||||
script, test_strings[i], test_strings[i], test_strings[i]);
|
||||
|
||||
JSValue match_result = JS_Eval(ctx, match_script, strlen(match_script),
|
||||
"<regexp-match>", 0);
|
||||
if (!JS_IsException(match_result)) {
|
||||
JS_FreeValue(ctx, match_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
const char* split_test = "'a,b,c,d'.split(/,/)";
|
||||
JSValue split_result = JS_Eval(ctx, split_test, strlen(split_test),
|
||||
"<regexp-split>", 0);
|
||||
if (!JS_IsException(split_result)) {
|
||||
JS_FreeValue(ctx, split_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* replace_test = "'hello world'.replace(/world/, 'universe')";
|
||||
JSValue replace_result = JS_Eval(ctx, replace_test, strlen(replace_test),
|
||||
"<regexp-replace>", 0);
|
||||
if (!JS_IsException(replace_result)) {
|
||||
JS_FreeValue(ctx, replace_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* search_test = "'abc123def'.search(/[0-9]+/)";
|
||||
JSValue search_result = JS_Eval(ctx, search_test, strlen(search_test),
|
||||
"<regexp-search>", 0);
|
||||
if (!JS_IsException(search_result)) {
|
||||
JS_FreeValue(ctx, search_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, regexp_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
char literal_script[4096];
|
||||
char slash_escaped[2048];
|
||||
size_t slash_idx = 0;
|
||||
for (size_t i = 0; i < pattern_len && slash_idx < sizeof(slash_escaped) - 2; i++) {
|
||||
if (pattern[i] == '/') {
|
||||
slash_escaped[slash_idx++] = '\\';
|
||||
}
|
||||
slash_escaped[slash_idx++] = pattern[i];
|
||||
}
|
||||
slash_escaped[slash_idx] = '\0';
|
||||
|
||||
snprintf(literal_script, sizeof(literal_script), "/%s/%s.test('test')", slash_escaped, valid_flags);
|
||||
|
||||
JSValue literal_result = JS_Eval(ctx, literal_script, strlen(literal_script),
|
||||
"<regexp-literal>", 0);
|
||||
if (!JS_IsException(literal_result)) {
|
||||
JS_FreeValue(ctx, literal_result);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
|
||||
const char* builtin_tests[] = {
|
||||
"RegExp.prototype.compile",
|
||||
"/a/g[Symbol.match]('a')",
|
||||
"/a/g[Symbol.replace]('a', 'b')",
|
||||
"/a/g[Symbol.search]('a')",
|
||||
"/a/g[Symbol.split]('a,b,a')",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(builtin_tests) / sizeof(builtin_tests[0]); i++) {
|
||||
JSValue r = JS_Eval(ctx, builtin_tests[i], strlen(builtin_tests[i]),
|
||||
"<regexp-builtin>", 0);
|
||||
if (!JS_IsException(r)) {
|
||||
JS_FreeValue(ctx, r);
|
||||
} else {
|
||||
JS_GetException(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
free(pattern);
|
||||
free(flags);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user