From c62a9fb92b102c90a66aa724cb9054183a33a68c Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 31 May 2022 21:48:46 -0700 Subject: [PATCH] Fixed catching of the exception thrown from an awaited function. This closes #500 issue on Github. --- src/njs_async.c | 6 ++--- test/js/async_try_catch_call.t.js | 29 +++++++++++++++++++++++++ test/js/async_try_catch_expression.t.js | 28 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 test/js/async_try_catch_call.t.js create mode 100644 test/js/async_try_catch_expression.t.js diff --git a/src/njs_async.c b/src/njs_async.c index e018bd8b..380c44b7 100644 --- a/src/njs_async.c +++ b/src/njs_async.c @@ -67,9 +67,6 @@ njs_await_fulfilled(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ctx = vm->top_frame->function->context; value = njs_arg(args, nargs, 1); - if (njs_is_error(value)) { - goto failed; - } async_frame = ctx->await; async = &async_frame->native; @@ -143,6 +140,7 @@ njs_await_rejected(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, value = njs_arg(args, nargs, 1); if (ctx->await->native.pc == ctx->pc) { + /* No catch block was set before await. */ (void) njs_function_call(vm, njs_function(&ctx->capability->reject), &njs_value_undefined, value, 1, &vm->retval); @@ -151,6 +149,8 @@ njs_await_rejected(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } + /* ctx->await->native.pc points to a catch block here. */ + ctx->pc = ctx->await->native.pc; return njs_await_fulfilled(vm, args, nargs, unused); diff --git a/test/js/async_try_catch_call.t.js b/test/js/async_try_catch_call.t.js new file mode 100644 index 00000000..6e8ef104 --- /dev/null +++ b/test/js/async_try_catch_call.t.js @@ -0,0 +1,29 @@ +/*--- +includes: [compareArray.js] +flags: [async] +---*/ + +let stages = []; +const fn = async () => { throw new Error('Oops') }; + +async function af() { + try { + await fn(); + + $DONOTEVALUATE(); + } + catch (v) { + stages.push(`catch:${v}`); + } + finally { + stages.push('finally'); + } + + return "end"; +}; + +af().then(v => { + stages.push(v); + assert.compareArray(stages, ['catch:Error: Oops', 'finally', 'end']); +}) +.then($DONE, $DONE) diff --git a/test/js/async_try_catch_expression.t.js b/test/js/async_try_catch_expression.t.js new file mode 100644 index 00000000..58d04203 --- /dev/null +++ b/test/js/async_try_catch_expression.t.js @@ -0,0 +1,28 @@ +/*--- +includes: [compareArray.js] +flags: [async] +---*/ + +let stages = []; + +async function af() { + try { + await ({}).a.a(); + + $DONOTEVALUATE(); + } + catch (v) { + stages.push('catch'); + } + finally { + stages.push('finally'); + } + + return "end"; +}; + +af().then(v => { + stages.push(v); + assert.compareArray(stages, ['catch', 'finally', 'end']); +}) +.then($DONE, $DONE) -- 2.47.3