Skip to content

Commit 2358d21

Browse files
committed
Fix reporting handled promises as unhandled in tracker
Enqueue a job which will perform the check after all reactions. Fixes: #39
1 parent 09d76ed commit 2358d21

File tree

3 files changed

+52
-15
lines changed

3 files changed

+52
-15
lines changed

quickjs.c

+34-12
Original file line numberDiff line numberDiff line change
@@ -50210,6 +50210,32 @@ static JSValue promise_reaction_job(JSContext *ctx, int argc,
5021050210
return res2;
5021150211
}
5021250212

50213+
static JSValue promise_rejection_tracker_job(JSContext *ctx, int argc,
50214+
JSValueConst *argv)
50215+
{
50216+
JSRuntime *rt;
50217+
JSPromiseData *s;
50218+
JSValueConst promise;
50219+
50220+
assert(argc == 1);
50221+
50222+
rt = ctx->rt;
50223+
promise = argv[0];
50224+
s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
50225+
50226+
if (!s || s->promise_state != JS_PROMISE_REJECTED)
50227+
return JS_UNDEFINED; /* should never happen */
50228+
50229+
promise_trace(ctx, "promise_rejection_tracker_job\n");
50230+
50231+
// Check again in case the hook was removed.
50232+
if (rt->host_promise_rejection_tracker)
50233+
rt->host_promise_rejection_tracker(
50234+
ctx, promise, s->promise_result, s->is_handled, rt->host_promise_rejection_tracker_opaque);
50235+
50236+
return JS_UNDEFINED;
50237+
}
50238+
5021350239
void JS_SetPromiseHook(JSRuntime *rt, JSPromiseHook promise_hook, void *opaque)
5021450240
{
5021550241
rt->promise_hook = promise_hook;
@@ -50247,14 +50273,6 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
5024750273
}
5024850274
}
5024950275

50250-
if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
50251-
JSRuntime *rt = ctx->rt;
50252-
if (rt->host_promise_rejection_tracker) {
50253-
rt->host_promise_rejection_tracker(ctx, promise, value, false,
50254-
rt->host_promise_rejection_tracker_opaque);
50255-
}
50256-
}
50257-
5025850276
list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
5025950277
rd = list_entry(el, JSPromiseReactionData, link);
5026050278
args[0] = rd->resolving_funcs[0];
@@ -50272,6 +50290,12 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
5027250290
list_del(&rd->link);
5027350291
promise_reaction_data_free(ctx->rt, rd);
5027450292
}
50293+
50294+
if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
50295+
JSRuntime *rt = ctx->rt;
50296+
if (rt->host_promise_rejection_tracker)
50297+
JS_EnqueueJob(ctx, promise_rejection_tracker_job, 1, &promise);
50298+
}
5027550299
}
5027650300

5027750301
static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
@@ -51018,10 +51042,8 @@ static __exception int perform_promise_then(JSContext *ctx,
5101851042
JSValueConst args[5];
5101951043
if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
5102051044
JSRuntime *rt = ctx->rt;
51021-
if (rt->host_promise_rejection_tracker) {
51022-
rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
51023-
true, rt->host_promise_rejection_tracker_opaque);
51024-
}
51045+
if (rt->host_promise_rejection_tracker)
51046+
JS_EnqueueJob(ctx, promise_rejection_tracker_job, 1, &promise);
5102551047
}
5102651048
i = s->promise_state - JS_PROMISE_FULFILLED;
5102751049
rd = rd_array[i];

run-test262.c

+12-3
Original file line numberDiff line numberDiff line change
@@ -1716,7 +1716,8 @@ JSContext *JS_NewCustomContext(JSRuntime *rt)
17161716
int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness,
17171717
namelist_t *ip, char *buf, size_t buf_len,
17181718
const char* error_type, int eval_flags, bool is_negative,
1719-
bool is_async, bool can_block, int *msec)
1719+
bool is_async, bool can_block, bool track_promise_rejections,
1720+
int *msec)
17201721
{
17211722
JSRuntime *rt;
17221723
JSContext *ctx;
@@ -1741,6 +1742,9 @@ int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness,
17411742
/* loader for ES6 modules */
17421743
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *) filename);
17431744

1745+
if (track_promise_rejections)
1746+
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL);
1747+
17441748
add_helpers(ctx);
17451749

17461750
for (i = 0; i < ip->count; i++) {
@@ -1787,6 +1791,7 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec)
17871791
int ret, eval_flags, use_strict, use_nostrict;
17881792
bool is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip;
17891793
bool detect_module = true;
1794+
bool track_promise_rejections = false;
17901795
bool can_block;
17911796
namelist_t include_list = { 0 }, *ip = &include_list;
17921797

@@ -1845,6 +1850,9 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec)
18451850
else if (str_equal(option, "qjs:no-detect-module")) {
18461851
detect_module = false;
18471852
}
1853+
else if (str_equal(option, "qjs:track-promise-rejections")) {
1854+
track_promise_rejections = true;
1855+
}
18481856
else if (str_equal(option, "module")) {
18491857
is_module = true;
18501858
skip |= skip_module;
@@ -1939,12 +1947,13 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec)
19391947
if (use_nostrict) {
19401948
ret = run_test_buf(tls, filename, harness, ip, buf, buf_len,
19411949
error_type, eval_flags, is_negative, is_async,
1942-
can_block, msec);
1950+
can_block, track_promise_rejections, msec);
19431951
}
19441952
if (use_strict) {
19451953
ret |= run_test_buf(tls, filename, harness, ip, buf, buf_len,
19461954
error_type, eval_flags | JS_EVAL_FLAG_STRICT,
1947-
is_negative, is_async, can_block, msec);
1955+
is_negative, is_async, can_block,
1956+
track_promise_rejections, msec);
19481957
}
19491958
}
19501959
namelist_free(&include_list);

tests/bug39.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*---
2+
flags: [qjs:track-promise-rejections]
3+
---*/
4+
5+
Promise.reject().catch(() => print('oops'))
6+
Promise.resolve().then(() => print('ok'))

0 commit comments

Comments
 (0)