Issue #2089 - Report unhandled rejection for optimized away promise

Based-on: m-c 1498775
This commit is contained in:
Martok 2023-01-27 19:31:17 +01:00 • committed by roytam1
commit a215929a31
2 changed files with 52 additions and 1 deletions

View file

@ -2299,8 +2299,25 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res
return Call(cx, calleeOrRval, UndefinedHandleValue, result, &calleeOrRval);
}
if (!promiseObj)
if (!promiseObj) {
if (mode == RejectMode) {
// The rejection will never be handled, given the returned promise
// is known to be unused, and already optimized away.
//
// Create temporary Promise object and reject it, in order to
// report the unhandled rejection.
//
// Allocation time points wrong time, but won't matter much.
Rooted<PromiseObject*> temporaryPromise(cx);
temporaryPromise = CreatePromiseObjectWithoutResolutionFunctions(cx);
if (!temporaryPromise) {
cx->clearPendingException();
return true;
}
return RejectPromiseInternal(cx, temporaryPromise, result);
}
return true;
}
Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>();
if (promise->state() != JS::PromiseState::Pending)

View file

@ -0,0 +1,34 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs setPromiseRejectionTrackerCallback
const UNHANDLED = 0;
const HANDLED = 1;
let rejections = new Map();
function rejectionTracker(promise, state) {
rejections.set(promise, state);
}
setPromiseRejectionTrackerCallback(rejectionTracker);
// If the return value of then is not used, the promise object is optimized
// away, but if a rejection happens, the rejection should be notified.
Promise.resolve().then(() => { throw 1; });
drainJobQueue();
assertEq(rejections.size, 1);
let [[promise, state]] = rejections;
assertEq(state, UNHANDLED);
let exc;
promise.catch(x => { exc = x; });
drainJobQueue();
// we handled it after all
assertEq(rejections.get(promise), HANDLED);
// the right exception was reported
assertEq(exc, 1);
if (this.reportCompare) {
reportCompare(true,true);
}