Bug 978232 - ES6 Proxies: [[Construct]] must throw if the trap doesn't return an object. (r=jwalden)
authorEric Faust <efaustbmo@gmail.com>
Tue, 15 Apr 2014 14:57:35 -0700
changeset 198287 037edc1bb5013508c3812bda29cadb3829368edb
parent 198286 299c11ed4f4c29245e5cc322cab58cb91d3ce332
child 198288 0c55cac422f2b9aadeecc005bfcd931e87f9e681
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs978232
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 978232 - ES6 Proxies: [[Construct]] must throw if the trap doesn't return an object. (r=jwalden)
js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
js/src/js.msg
js/src/jsproxy.cpp
js/src/tests/ecma_6/Proxy/proxy-constructNonObject.js
--- a/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
@@ -1,15 +1,18 @@
+load(libdir + "asserts.js");
 /*
  * Call the trap with the handler as the this value, the target as the first
  * argument, and the original arguments as the third argument.
+ *
+ * Hooks that don't return an object must throw.
  */
 var target = function () {};
 var handler = {
     construct: function (target1, args) {
         assertEq(this, handler);
         assertEq(target1, target);
         assertEq(args.length, 2);
         assertEq(args[0], 2);
         assertEq(args[1], 3);
     }
 }
-assertEq(new (new Proxy(target, handler))(2, 3), undefined);
+assertThrowsInstanceOf(function () {new (new Proxy(target, handler))(2, 3)}, TypeError);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -433,8 +433,9 @@ MSG_DEF(JSMSG_NO_EXPORT_NAME,           
 MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
 MSG_DEF(JSMSG_INVALID_PROTOTYPE,        380, 0, JSEXN_TYPEERR, "prototype field is not an object")
 MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
 MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
 MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
 MSG_DEF(JSMSG_TERMINATED,               384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
 MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP, 385, 1, JSEXN_ERR, "No such property on self-hosted object: {0}")
 MSG_DEF(JSMSG_PROXY_EXTENSIBILITY,      386, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
+MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT,   387, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object")
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2343,17 +2343,23 @@ ScriptedDirectProxyHandler::construct(JS
         return DirectProxyHandler::construct(cx, proxy, args);
 
     // step 6
     Value constructArgv[] = {
         ObjectValue(*target),
         ObjectValue(*argsArray)
     };
     RootedValue thisValue(cx, ObjectValue(*handler));
-    return Invoke(cx, thisValue, trap, ArrayLength(constructArgv), constructArgv, args.rval());
+    if (!Invoke(cx, thisValue, trap, ArrayLength(constructArgv), constructArgv, args.rval()))
+        return false;
+    if (!args.rval().isObject()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_PROXY_CONSTRUCT_OBJECT);
+        return false;
+    }
+    return true;
 }
 
 ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
 
 #define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall)                   \
     JS_BEGIN_MACRO                                                           \
         RootedObject proto(cx);                                              \
         if (!JSObject::getProto(cx, proxy, &proto))                          \
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Proxy/proxy-constructNonObject.js
@@ -0,0 +1,18 @@
+function bogusConstruct(target) { return 4; }
+function bogusConstructUndefined(target) { }
+
+var handler = { construct: bogusConstruct }
+
+function callable() {}
+
+var p = new Proxy(callable, handler);
+
+assertThrowsInstanceOf(function () { new p(); }, TypeError,
+                       "[[Construct must throw if an object is not returned.");
+
+handler.construct = bogusConstructUndefined;
+assertThrowsInstanceOf(function () { new p(); }, TypeError,
+                       "[[Construct must throw if an object is not returned.");
+
+if (typeof reportCompare === "function")
+    reportCompare(0,0, "OK");