Check that Promise subclasses have callable resolve/reject
This check is guaranteed by the Promise spec and tested by test262 tests. It only has to run for subclasses. This patch adds the check to the Promise code. BUG=v8:4633 R=adamk LOG=Y Review URL: https://codereview.chromium.org/1780823003 Cr-Commit-Position: refs/heads/master@{#34693}
This commit is contained in:
parent
dea9559457
commit
d9c45337a4
@ -217,8 +217,6 @@ function PromiseReject(promise, r) {
|
||||
PromiseDone(promise, -1, r, promiseOnRejectSymbol)
|
||||
}
|
||||
|
||||
// Convenience.
|
||||
|
||||
function NewPromiseCapability(C) {
|
||||
if (C === GlobalPromise) {
|
||||
// Optimized case, avoid extra closure.
|
||||
@ -239,6 +237,9 @@ function NewPromiseCapability(C) {
|
||||
result.reject = reject;
|
||||
});
|
||||
|
||||
if (!IS_CALLABLE(result.resolve) || !IS_CALLABLE(result.reject))
|
||||
throw MakeTypeError(kPromiseNonCallable);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -187,6 +187,7 @@ class CallSite {
|
||||
T(PromiseCyclic, "Chaining cycle detected for promise %") \
|
||||
T(PromiseExecutorAlreadyInvoked, \
|
||||
"Promise executor has already been invoked with non-undefined arguments") \
|
||||
T(PromiseNonCallable, "Promise resolve or reject function is not callable") \
|
||||
T(PropertyDescObject, "Property description must be an object: %") \
|
||||
T(PropertyNotFunction, \
|
||||
"'%' returned for property '%' of object '%' is not a function") \
|
||||
|
@ -2,18 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --expose-debug-as debug --allow-natives-syntax --promise-extra
|
||||
|
||||
// Test debug events when an exception is thrown inside a Promise, which is
|
||||
// caught by a custom promise, which has no reject handler.
|
||||
// We expect two Exception debug events:
|
||||
// 1) when the exception is thrown in the promise q.
|
||||
// 2) when calling the undefined custom reject closure in MyPromise throws.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var expected_events = 2;
|
||||
var log = [];
|
||||
// A non-callable reject function throws eagerly
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
@ -23,7 +12,6 @@ var p = new Promise(function(resolve, reject) {
|
||||
function MyPromise(resolver) {
|
||||
var reject = undefined;
|
||||
var resolve = function() { };
|
||||
log.push("construct");
|
||||
resolver(resolve, reject);
|
||||
};
|
||||
|
||||
@ -31,56 +19,4 @@ MyPromise.prototype = new Promise(function() {});
|
||||
MyPromise.__proto__ = Promise;
|
||||
p.constructor = MyPromise;
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw caught");
|
||||
throw new Error("caught"); // event
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
if (event == Debug.DebugEvent.Exception) {
|
||||
expected_events--;
|
||||
assertTrue(expected_events >= 0);
|
||||
if (expected_events == 1) {
|
||||
assertTrue(
|
||||
exec_state.frame(0).sourceLineText().indexOf('// event') > 0);
|
||||
assertEquals("caught", event_data.exception().message);
|
||||
} else if (expected_events == 0) {
|
||||
// All of the frames on the stack are from native Javascript.
|
||||
assertEquals(0, exec_state.frameCount());
|
||||
assertEquals("(var).reject is not a function",
|
||||
event_data.exception().message);
|
||||
} else {
|
||||
assertUnreachable();
|
||||
}
|
||||
assertSame(q, event_data.promise());
|
||||
}
|
||||
} catch (e) {
|
||||
%AbortJS(e + "\n" + e.stack);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnUncaughtException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
||||
|
||||
function testDone(iteration) {
|
||||
function checkResult() {
|
||||
try {
|
||||
assertTrue(iteration < 10);
|
||||
if (expected_events === 0) {
|
||||
assertEquals(["resolve", "construct", "end main", "throw caught"], log);
|
||||
} else {
|
||||
testDone(iteration + 1);
|
||||
}
|
||||
} catch (e) {
|
||||
%AbortJS(e + "\n" + e.stack);
|
||||
}
|
||||
}
|
||||
|
||||
%EnqueueMicrotask(checkResult);
|
||||
}
|
||||
|
||||
testDone(0);
|
||||
assertThrows(()=> p.then(function() { }), TypeError);
|
||||
|
@ -174,12 +174,6 @@
|
||||
'built-ins/Promise/resolve-function-name': [FAIL],
|
||||
'built-ins/Promise/all/resolve-element-function-name': [FAIL],
|
||||
'built-ins/Promise/executor-function-name': [FAIL],
|
||||
'built-ins/Promise/all/capability-executor-not-callable': [FAIL],
|
||||
'built-ins/Promise/reject/capability-executor-not-callable': [FAIL],
|
||||
'built-ins/Promise/race/capability-executor-not-callable': [FAIL],
|
||||
'built-ins/Promise/prototype/then/capability-executor-not-callable': [FAIL],
|
||||
'built-ins/Promise/resolve/capability-executor-not-callable': [FAIL],
|
||||
'built-ins/Promise/race/S25.4.4.3_A3.1_T2': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=4634
|
||||
'built-ins/DataView/prototype/setFloat64/index-check-before-value-conversion': [FAIL],
|
||||
|
Loading…
Reference in New Issue
Block a user