Skip to content

Commit bb14020

Browse files
authored
Refactor Error.stackTraceLimit
- Store the JS value, so the conversion happens when the backtrace is needed - Prevent recursion in build_backtrace - Simplify code for saving / restoring exception in build_backtrace
1 parent 582aed2 commit bb14020

File tree

2 files changed

+51
-25
lines changed

2 files changed

+51
-25
lines changed

quickjs.c

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ struct JSRuntime {
249249
JSValue current_exception;
250250
/* true if inside an out of memory error, to avoid recursing */
251251
bool in_out_of_memory;
252-
/* and likewise if inside Error.prepareStackTrace() */
253-
bool in_prepare_stack_trace;
252+
/* true if inside build_backtrace, to avoid recursing */
253+
bool in_build_stack_trace;
254254
/* true if inside JS_FreeRuntime */
255255
bool in_free;
256256

@@ -396,7 +396,7 @@ struct JSContext {
396396
JSValue error_ctor;
397397
JSValue error_back_trace;
398398
JSValue error_prepare_stack;
399-
int error_stack_trace_limit;
399+
JSValue error_stack_trace_limit;
400400
JSValue iterator_ctor;
401401
JSValue iterator_proto;
402402
JSValue async_iterator_proto;
@@ -2311,7 +2311,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
23112311
ctx->error_ctor = JS_NULL;
23122312
ctx->error_back_trace = JS_UNDEFINED;
23132313
ctx->error_prepare_stack = JS_UNDEFINED;
2314-
ctx->error_stack_trace_limit = 10;
2314+
ctx->error_stack_trace_limit = js_int32(10);
23152315
init_list_head(&ctx->loaded_modules);
23162316

23172317
JS_AddIntrinsicBasicObjects(ctx);
@@ -2431,6 +2431,7 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
24312431
JS_MarkValue(rt, ctx->error_ctor, mark_func);
24322432
JS_MarkValue(rt, ctx->error_back_trace, mark_func);
24332433
JS_MarkValue(rt, ctx->error_prepare_stack, mark_func);
2434+
JS_MarkValue(rt, ctx->error_stack_trace_limit, mark_func);
24342435
for(i = 0; i < rt->class_count; i++) {
24352436
JS_MarkValue(rt, ctx->class_proto[i], mark_func);
24362437
}
@@ -2499,6 +2500,7 @@ void JS_FreeContext(JSContext *ctx)
24992500
JS_FreeValue(ctx, ctx->error_ctor);
25002501
JS_FreeValue(ctx, ctx->error_back_trace);
25012502
JS_FreeValue(ctx, ctx->error_prepare_stack);
2503+
JS_FreeValue(ctx, ctx->error_stack_trace_limit);
25022504
for(i = 0; i < rt->class_count; i++) {
25032505
JS_FreeValue(ctx, ctx->class_proto[i]);
25042506
}
@@ -6751,26 +6753,43 @@ static void build_backtrace(JSContext *ctx, JSValue error_val, JSValue filter_fu
67516753
JSRuntime *rt;
67526754
JSCallSiteData csd[64];
67536755
uint32_t i;
6756+
double d;
67546757
int stack_trace_limit;
67556758

6759+
rt = ctx->rt;
6760+
if (rt->in_build_stack_trace)
6761+
return;
6762+
rt->in_build_stack_trace = true;
6763+
6764+
// Save exception because conversion to double may fail.
6765+
saved_exception = JS_GetException(ctx);
6766+
6767+
// Extract stack trace limit.
6768+
JS_ToFloat64(ctx, &d, ctx->error_stack_trace_limit);
6769+
if (isnan(d) || d < 0.0)
6770+
stack_trace_limit = 0;
6771+
else if (d > INT32_MAX)
6772+
stack_trace_limit = INT32_MAX;
6773+
else
6774+
stack_trace_limit = fabs(d);
6775+
6776+
// Restore current exception.
6777+
JS_Throw(ctx, saved_exception);
67566778
saved_exception = JS_UNINITIALIZED;
6757-
stack_trace_limit = ctx->error_stack_trace_limit;
6779+
67586780
stack_trace_limit = min_int(stack_trace_limit, countof(csd));
67596781
stack_trace_limit = max_int(stack_trace_limit, 0);
6760-
rt = ctx->rt;
67616782
has_prepare = false;
67626783
has_filter_func = backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC;
67636784
i = 0;
67646785

6765-
if (!rt->in_prepare_stack_trace && !JS_IsNull(ctx->error_ctor)) {
6786+
if (!JS_IsNull(ctx->error_ctor)) {
67666787
prepare = js_dup(ctx->error_prepare_stack);
67676788
has_prepare = JS_IsFunction(ctx, prepare);
6768-
rt->in_prepare_stack_trace = true;
67696789
}
67706790

67716791
if (has_prepare) {
6772-
saved_exception = rt->current_exception;
6773-
rt->current_exception = JS_UNINITIALIZED;
6792+
saved_exception = JS_GetException(ctx);
67746793
if (stack_trace_limit == 0)
67756794
goto done;
67766795
if (filename)
@@ -6894,8 +6913,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_val, JSValue filter_fu
68946913
else
68956914
stack = stack2;
68966915
JS_FreeValue(ctx, prepare);
6897-
JS_FreeValue(ctx, rt->current_exception);
6898-
rt->current_exception = saved_exception;
6916+
JS_Throw(ctx, saved_exception);
68996917
} else {
69006918
if (dbuf_error(&dbuf))
69016919
stack = JS_NULL;
@@ -6904,7 +6922,6 @@ static void build_backtrace(JSContext *ctx, JSValue error_val, JSValue filter_fu
69046922
dbuf_free(&dbuf);
69056923
}
69066924

6907-
rt->in_prepare_stack_trace = false;
69086925
if (JS_IsUndefined(ctx->error_back_trace))
69096926
ctx->error_back_trace = js_dup(stack);
69106927
if (has_filter_func || can_add_backtrace(error_val)) {
@@ -6913,6 +6930,8 @@ static void build_backtrace(JSContext *ctx, JSValue error_val, JSValue filter_fu
69136930
} else {
69146931
JS_FreeValue(ctx, stack);
69156932
}
6933+
6934+
rt->in_build_stack_trace = false;
69166935
}
69176936

69186937
JSValue JS_NewError(JSContext *ctx)
@@ -38154,23 +38173,14 @@ static JSValue js_error_get_stackTraceLimit(JSContext *ctx, JSValue this_val)
3815438173
if (JS_IsException(val))
3815538174
return val;
3815638175
JS_FreeValue(ctx, val);
38157-
return js_int32(ctx->error_stack_trace_limit);
38176+
return js_dup(ctx->error_stack_trace_limit);
3815838177
}
3815938178

3816038179
static JSValue js_error_set_stackTraceLimit(JSContext *ctx, JSValue this_val, JSValue value)
3816138180
{
3816238181
if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
3816338182
return JS_ThrowTypeErrorNotAnObject(ctx);
38164-
double limit = 0;
38165-
if (JS_ToFloat64(ctx, &limit, value) < 0)
38166-
return JS_EXCEPTION;
38167-
if (isfinite(limit)) {
38168-
ctx->error_stack_trace_limit = limit;
38169-
} else if (isnan(limit) || limit == -INFINITY) {
38170-
ctx->error_stack_trace_limit = 0;
38171-
} else {
38172-
ctx->error_stack_trace_limit = INT32_MAX;
38173-
}
38183+
ctx->error_stack_trace_limit = js_dup(value);
3817438184
return JS_UNDEFINED;
3817538185
}
3817638186

tests/bug858.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
import {assert} from "./assert.js";
22

33
Error.stackTraceLimit = Infinity;
4+
assert(Error.stackTraceLimit === Infinity);
45
assert(new Error("error").stack.includes("bug858.js")); // stack should not be empty
56

67
Error.stackTraceLimit = -Infinity;
8+
assert(Error.stackTraceLimit === -Infinity);
79
assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty
810

911
Error.stackTraceLimit = NaN;
10-
assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty
12+
assert(Number.isNaN(Error.stackTraceLimit));
13+
assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty
14+
15+
Error.stackTraceLimit = -0;
16+
assert(Object.is(Error.stackTraceLimit, -0));
17+
assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty
18+
19+
const obj = { valueOf() { throw "evil" } };
20+
Error.stackTraceLimit = obj;
21+
assert(Error.stackTraceLimit === obj);
22+
try {
23+
throw new Error("fail")
24+
} catch (e) {
25+
assert(e.message.includes("fail"));
26+
}

0 commit comments

Comments
 (0)