@@ -394,6 +394,7 @@ struct JSContext {
394
394
JSValue promise_ctor;
395
395
JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
396
396
JSValue error_ctor;
397
+ JSValue error_back_trace;
397
398
JSValue error_prepare_stack;
398
399
int error_stack_trace_limit;
399
400
JSValue iterator_ctor;
@@ -2305,6 +2306,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
2305
2306
ctx->regexp_ctor = JS_NULL;
2306
2307
ctx->promise_ctor = JS_NULL;
2307
2308
ctx->error_ctor = JS_NULL;
2309
+ ctx->error_back_trace = JS_UNDEFINED;
2308
2310
ctx->error_prepare_stack = JS_UNDEFINED;
2309
2311
ctx->error_stack_trace_limit = 10;
2310
2312
init_list_head(&ctx->loaded_modules);
@@ -2424,6 +2426,7 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2424
2426
JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
2425
2427
}
2426
2428
JS_MarkValue(rt, ctx->error_ctor, mark_func);
2429
+ JS_MarkValue(rt, ctx->error_back_trace, mark_func);
2427
2430
JS_MarkValue(rt, ctx->error_prepare_stack, mark_func);
2428
2431
for(i = 0; i < rt->class_count; i++) {
2429
2432
JS_MarkValue(rt, ctx->class_proto[i], mark_func);
@@ -2491,6 +2494,7 @@ void JS_FreeContext(JSContext *ctx)
2491
2494
JS_FreeValue(ctx, ctx->native_error_proto[i]);
2492
2495
}
2493
2496
JS_FreeValue(ctx, ctx->error_ctor);
2497
+ JS_FreeValue(ctx, ctx->error_back_trace);
2494
2498
JS_FreeValue(ctx, ctx->error_prepare_stack);
2495
2499
for(i = 0; i < rt->class_count; i++) {
2496
2500
JS_FreeValue(ctx, ctx->class_proto[i]);
@@ -6616,14 +6620,28 @@ static const char *get_func_name(JSContext *ctx, JSValue func)
6616
6620
return JS_ToCString(ctx, val);
6617
6621
}
6618
6622
6623
+ /* Note: it is important that no exception is returned by this function */
6624
+ static bool can_add_backtrace(JSValue obj)
6625
+ {
6626
+ JSObject *p;
6627
+ if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6628
+ return false;
6629
+ p = JS_VALUE_GET_OBJ(obj);
6630
+ if (p->class_id != JS_CLASS_ERROR)
6631
+ return false;
6632
+ if (find_own_property1(p, JS_ATOM_stack))
6633
+ return false;
6634
+ return true;
6635
+ }
6636
+
6619
6637
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6620
6638
/* only taken into account if filename is provided */
6621
6639
#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
6622
6640
#define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2)
6623
6641
6624
6642
/* if filename != NULL, an additional level is added with the filename
6625
6643
and line number information (used for parse error). */
6626
- static void build_backtrace(JSContext *ctx, JSValue error_obj , JSValue filter_func,
6644
+ static void build_backtrace(JSContext *ctx, JSValue error_val , JSValue filter_func,
6627
6645
const char *filename, int line_num, int col_num,
6628
6646
int backtrace_flags)
6629
6647
{
@@ -6717,23 +6735,24 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
6717
6735
dbuf_printf(&dbuf, " at %s", str1);
6718
6736
JS_FreeCString(ctx, func_name_str);
6719
6737
6720
- if (b) {
6738
+ if (b && sf->cur_pc ) {
6721
6739
const char *atom_str;
6722
6740
int line_num1, col_num1;
6741
+ uint32_t pc;
6723
6742
6724
- /* Bytecode functions must have cur_pc set in the stack frame. */
6725
- if (sf->cur_pc == NULL)
6726
- abort();
6727
-
6728
- line_num1 = find_line_num(ctx, b,
6729
- sf->cur_pc - b->byte_code_buf - 1,
6730
- &col_num1);
6743
+ pc = sf->cur_pc - b->byte_code_buf - 1;
6744
+ line_num1 = find_line_num(ctx, b, pc, &col_num1);
6731
6745
atom_str = b->filename ? JS_AtomToCString(ctx, b->filename) : NULL;
6732
6746
dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : "<null>");
6733
6747
JS_FreeCString(ctx, atom_str);
6734
6748
if (line_num1 != -1)
6735
6749
dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
6736
6750
dbuf_putc(&dbuf, ')');
6751
+ } else if (b) {
6752
+ // FIXME(bnoordhuis) Missing `sf->cur_pc = pc` in bytecode
6753
+ // handler in JS_CallInternal. Almost never user observable
6754
+ // except with intercepting JS proxies that throw exceptions.
6755
+ dbuf_printf(&dbuf, " (missing)");
6737
6756
} else {
6738
6757
dbuf_printf(&dbuf, " (native)");
6739
6758
}
@@ -6769,7 +6788,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
6769
6788
JS_FreeValue(ctx, csd[k].func_name);
6770
6789
}
6771
6790
JSValue args[] = {
6772
- error_obj ,
6791
+ error_val ,
6773
6792
stack,
6774
6793
};
6775
6794
JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args);
@@ -6790,21 +6809,14 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
6790
6809
}
6791
6810
6792
6811
rt->in_prepare_stack_trace = false;
6793
- JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, stack, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6794
- }
6795
-
6796
- /* Note: it is important that no exception is returned by this function */
6797
- static bool is_backtrace_needed(JSContext *ctx, JSValue obj)
6798
- {
6799
- JSObject *p;
6800
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6801
- return false;
6802
- p = JS_VALUE_GET_OBJ(obj);
6803
- if (p->class_id != JS_CLASS_ERROR)
6804
- return false;
6805
- if (find_own_property1(p, JS_ATOM_stack))
6806
- return false;
6807
- return true;
6812
+ if (JS_IsUndefined(ctx->error_back_trace))
6813
+ ctx->error_back_trace = js_dup(stack);
6814
+ if (can_add_backtrace(error_val)) {
6815
+ JS_DefinePropertyValue(ctx, error_val, JS_ATOM_stack, stack,
6816
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6817
+ } else {
6818
+ JS_FreeValue(ctx, stack);
6819
+ }
6808
6820
}
6809
6821
6810
6822
JSValue JS_NewError(JSContext *ctx)
@@ -17432,13 +17444,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
17432
17444
}
17433
17445
}
17434
17446
exception:
17435
- if (is_backtrace_needed(ctx, rt->current_exception)) {
17436
- /* add the backtrace information now (it is not done
17437
- before if the exception happens in a bytecode
17438
- operation */
17439
- sf->cur_pc = pc;
17440
- build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0);
17441
- }
17447
+ sf->cur_pc = pc;
17448
+ build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0);
17442
17449
if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
17443
17450
while (sp > stack_buf) {
17444
17451
JSValue val = *--sp;
@@ -17453,6 +17460,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
17453
17460
} else {
17454
17461
*sp++ = rt->current_exception;
17455
17462
rt->current_exception = JS_UNINITIALIZED;
17463
+ JS_FreeValueRT(rt, ctx->error_back_trace);
17464
+ ctx->error_back_trace = JS_UNDEFINED;
17456
17465
pc = b->byte_code_buf + pos;
17457
17466
goto restart;
17458
17467
}
@@ -56163,7 +56172,9 @@ bool JS_DetectModule(const char *input, size_t input_len)
56163
56172
}
56164
56173
56165
56174
uintptr_t js_std_cmd(int cmd, ...) {
56175
+ JSContext *ctx;
56166
56176
JSRuntime *rt;
56177
+ JSValue *pv;
56167
56178
uintptr_t rv;
56168
56179
va_list ap;
56169
56180
@@ -56178,6 +56189,12 @@ uintptr_t js_std_cmd(int cmd, ...) {
56178
56189
rt = va_arg(ap, JSRuntime *);
56179
56190
rt->libc_opaque = va_arg(ap, void *);
56180
56191
break;
56192
+ case 2: // ErrorBackTrace
56193
+ ctx = va_arg(ap, JSContext *);
56194
+ pv = va_arg(ap, JSValue *);
56195
+ *pv = ctx->error_back_trace;
56196
+ ctx->error_back_trace = JS_UNDEFINED;
56197
+ break;
56181
56198
default:
56182
56199
rv = -1;
56183
56200
}
0 commit comments