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:
littledan 2016-03-10 15:20:39 -08:00 committed by Commit bot
parent dea9559457
commit d9c45337a4
4 changed files with 6 additions and 74 deletions

View File

@ -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;
}

View File

@ -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") \

View File

@ -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);

View File

@ -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],