add asan error vm stacktrace
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user