add asan error vm stacktrace

This commit is contained in:
2026-02-06 21:49:53 -06:00
parent ea185dbffd
commit 024d796ca4

View File

@@ -128,6 +128,10 @@
#endif
#endif /* POISON_HEAP */
#ifdef HAVE_ASAN
static struct JSContext *__asan_js_ctx;
#endif
/* Forward declarations for heap object types */
typedef struct JSArray JSArray;
typedef struct JSBlob JSBlob;
@@ -30065,7 +30069,6 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr
/* Unary ops */
if (strcmp (kind, "!") == 0 || strcmp (kind, "~") == 0 ||
strcmp (kind, "typeof") == 0 ||
strcmp (kind, "delete") == 0 || strcmp (kind, "neg") == 0 ||
strcmp (kind, "pos") == 0 || strcmp (kind, "spread") == 0) {
ast_sem_check_expr (st, scope, cJSON_GetObjectItem (expr, "expression"));
@@ -32037,6 +32040,50 @@ static int reg_vm_check_interrupt(JSContext *ctx) {
return 0;
}
#ifdef HAVE_ASAN
void __asan_on_error(void) {
JSContext *ctx = __asan_js_ctx;
if (!ctx) return;
if (JS_IsNull(ctx->reg_current_frame)) return;
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(ctx->reg_current_frame);
uint32_t cur_pc = ctx->rt->current_register_pc;
fprintf(stderr, "\n=== ASAN error: VM stack trace ===\n");
int is_first = 1;
while (frame) {
if (!JS_IsFunction(frame->function)) break;
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
const char *func_name = NULL;
const char *file = NULL;
uint16_t line = 0;
uint32_t pc = is_first ? cur_pc : 0;
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
JSCodeRegister *code = fn->u.reg.code;
file = code->filename_cstr;
func_name = code->name_cstr;
if (!is_first)
pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
if (code->line_table && pc < code->instr_count)
line = code->line_table[pc].line;
} else if (fn->kind == JS_FUNC_KIND_MCODE && fn->u.mcode.code) {
JSMCode *code = fn->u.mcode.code;
file = code->filename;
func_name = code->name;
if (!is_first)
pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
if (code->line_table && pc < code->instr_count)
line = code->line_table[pc].line;
}
fprintf(stderr, " %s (%s:%u)\n",
func_name ? func_name : "<anonymous>",
file ? file : "<unknown>", line);
if (JS_IsNull(frame->caller)) break;
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
is_first = 0;
}
fprintf(stderr, "=================================\n");
}
#endif
/* Main register VM execution loop */
static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSValue this_obj, int argc, JSValue *argv,
@@ -32049,6 +32096,9 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSGCRef frame_ref;
JS_AddGCRef(ctx, &frame_ref);
frame_ref.val = JS_MKPTR(frame);
#ifdef HAVE_ASAN
__asan_js_ctx = ctx;
#endif
/* Setup initial frame — wrap top-level code in a function object so that
returning from a called register function can read code/env from frame */
@@ -32093,6 +32143,8 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
}
MachInstr32 instr = code->instructions[pc++];
ctx->reg_current_frame = frame_ref.val;
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;
int op = MACH_GET_OP(instr);
int a = MACH_GET_A(instr);
int b = MACH_GET_B(instr);
@@ -32357,10 +32409,13 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
if (fn->kind == JS_FUNC_KIND_C) {
/* C function: call directly with args from consecutive slots */
/* C function: copy args to C stack so GC can't invalidate argv */
JSValue c_argv[nargs > 0 ? nargs : 1];
for (int i = 0; i < nargs; i++)
c_argv[i] = frame->slots[base + 1 + i];
ctx->reg_current_frame = frame_ref.val;
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &frame->slots[base + 1]);
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, c_argv);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
ctx->reg_current_frame = JS_NULL;
if (JS_IsException(ret)) { goto disrupt; }
@@ -32369,7 +32424,10 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
/* Register function: allocate frame, copy args, switch */
JSCodeRegister *fn_code = fn->u.reg.code;
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
if (!new_frame) { goto disrupt; }
if (!new_frame) {
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
}
/* Re-read pointers — GC may have moved them */
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
func_val = frame->slots[base];
@@ -32390,8 +32448,11 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
env = fn->u.reg.env_record;
pc = code->entry_point;
} else {
/* Other function kinds (bytecode) — call via C bridge */
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &frame->slots[base + 1]);
/* Other function kinds (bytecode) — copy args to C stack */
JSValue bc_argv[nargs > 0 ? nargs : 1];
for (int i = 0; i < nargs; i++)
bc_argv[i] = frame->slots[base + 1 + i];
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, bc_argv);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(ret)) { goto disrupt; }
if (nresults > 0) frame->slots[base] = ret;
@@ -32501,6 +32562,10 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
}
done:
#ifdef HAVE_ASAN
__asan_js_ctx = NULL;
#endif
ctx->reg_current_frame = JS_NULL;
if (JS_IsException(result)) {
ctx->reg_current_frame = frame_ref.val;
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;