From: Dmitry Volyntsev Date: Thu, 16 Jun 2022 00:10:39 +0000 (-0700) Subject: Propertly handling NJS_DECLINE in promise native functions. X-Git-Tag: 0.7.5~2 X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=b403e2e83eb417e43c01707691b2092393d1911d;p=njs.git Propertly handling NJS_DECLINE in promise native functions. Previously, NJS_DECLINE was returned from a Promise.all() and friends when "resolve" property was not found in a promise constructor. NJS_DECLINE was treated as NJS_ERROR in one place, but as NJS_OK in a different place during the promise function evaluation. As a result, the VM was left in inconsistent state during stack unwinding which resulted in a garbage return value. The fix is to ensure that only NJS_ERROR or NJS_OK is returned from ordinary native functions. This closes #545 issue on Github. --- diff --git a/src/njs_promise.c b/src/njs_promise.c index bfde8cce..fca8e6d6 100644 --- a/src/njs_promise.c +++ b/src/njs_promise.c @@ -389,7 +389,7 @@ njs_promise_value_constructor(njs_vm_t *vm, njs_value_t *value, ret = njs_value_property(vm, value, njs_value_arg(&string_constructor), dst); - if (njs_slow_path(ret != NJS_OK)) { + if (njs_slow_path(ret == NJS_ERROR)) { return ret; } @@ -1255,7 +1255,7 @@ njs_promise_all(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_value_property(vm, promise_ctor, njs_value_arg(&string_resolve), &resolve); - if (njs_slow_path(ret != NJS_OK)) { + if (njs_slow_path(ret == NJS_ERROR)) { return ret; } @@ -1715,7 +1715,7 @@ njs_promise_race(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_value_property(vm, promise_ctor, njs_value_arg(&string_resolve), &resolve); - if (njs_slow_path(ret != NJS_OK)) { + if (njs_slow_path(ret == NJS_ERROR)) { return ret; } diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index d338c79f..1841de1e 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -21211,6 +21211,28 @@ static njs_unit_test_t njs_externals_test[] = { njs_str("$r.retval(Promise.all([async () => [await x('X')]]))"), njs_str("[object Promise]") }, + { njs_str("var r = [1].map(v => {" + " function C(a) {" + " a(a, parseInt);" + " };" + "" + " Promise.all.apply(C);" + "});" + "r[0]"), + /* TODO: RejectAbrupt() exception should not percolate */ + njs_str("TypeError: resolve is not callable") }, + + { njs_str("var r = [1].map(v => {" + " function C(a) {" + " a(a, parseInt);" + " };" + "" + " Promise.race.apply(C);" + "});" + "r[0]"), + /* TODO: RejectAbrupt() exception should not percolate */ + njs_str("TypeError: resolve is not callable") }, + { njs_str("let obj = { a: 1, b: 2};" "function cb(r) { r.retval(obj.a); }" "$r.subrequest($r)"