From e9f2cb466c06a10ad43d0969ac689b45730fade5 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 7 Apr 2015 18:19:26 +0900 Subject: [PATCH] Bug 1151149 - Throw if either the target or handler is a revoked proxy in Proxy constructor. r=efaust --- js/src/js.msg | 1 + js/src/proxy/ScriptedDirectProxyHandler.cpp | 32 ++++++++++- .../Proxy/proxy-with-revoked-arguments.js | 53 +++++++++++++++++++ js/src/vm/Xdr.h | 4 +- 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js diff --git a/js/src/js.msg b/js/src/js.msg index 79b33981268..30c7d2371b9 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -369,6 +369,7 @@ MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT, 0, JSEXN_TYPEERR, "proxy [[Construct]] mu MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target") MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined") MSG_DEF(JSMSG_PROXY_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy") +MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy") // Structured cloning MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clone version") diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index dfd415c8445..568aa49df01 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -1175,6 +1175,14 @@ ScriptedDirectProxyHandler::isConstructor(JSObject* obj) const const char ScriptedDirectProxyHandler::family = 0; const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton; +bool +IsRevokedScriptedProxy(JSObject* obj) +{ + obj = CheckedUnwrap(obj); + return obj && IsScriptedProxy(obj) && !obj->as().target(); +} + +// ES6 draft rc4 9.5.15. static bool NewScriptedProxy(JSContext* cx, CallArgs& args, const char* callerName) { @@ -1183,26 +1191,48 @@ NewScriptedProxy(JSContext* cx, CallArgs& args, const char* callerName) callerName, "1", "s"); return false; } + + // Step 1. RootedObject target(cx, NonNullObject(cx, args[0])); if (!target) return false; + + // Step 2. + if (IsRevokedScriptedProxy(target)) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "1"); + return false; + } + + // Step 3. RootedObject handler(cx, NonNullObject(cx, args[1])); if (!handler) return false; + + // Step 4. + if (IsRevokedScriptedProxy(handler)) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "2"); + return false; + } + + // Steps 5-6, and 8 (reordered). RootedValue priv(cx, ObjectValue(*target)); JSObject* proxy_ = NewProxyObject(cx, &ScriptedDirectProxyHandler::singleton, priv, TaggedProto::LazyProto); if (!proxy_) return false; + + // Step 9 (reordered). Rooted proxy(cx, &proxy_->as()); proxy->setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler)); - // Assign [[Call]] and [[Construct]] + // Step 7, Assign [[Call]] and [[Construct]]. uint32_t callable = target->isCallable() ? ScriptedDirectProxyHandler::IS_CALLABLE : 0; uint32_t constructor = target->isConstructor() ? ScriptedDirectProxyHandler::IS_CONSTRUCTOR : 0; proxy->as().setExtra(ScriptedDirectProxyHandler::IS_CALLCONSTRUCT_EXTRA, PrivateUint32Value(callable | constructor)); + + // Step 10. args.rval().setObject(*proxy); return true; } diff --git a/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js new file mode 100644 index 00000000000..e0ae15acf8a --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js @@ -0,0 +1,53 @@ +var BUGNUMBER = 1151149; +var summary = "Proxy constructor should throw if either the target or handler is a revoked proxy."; + +print(BUGNUMBER + ": " + summary); + +var p = new Proxy({}, {}); + +new Proxy(p, {}); +new Proxy({}, p); + +var r = Proxy.revocable({}, {}); +p = r.proxy; + +new Proxy(p, {}); +new Proxy({}, p); + +r.revoke(); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + + +var r2 = Proxy.revocable({}, {}); +r = Proxy.revocable(r2.proxy, {}); +p = r.proxy; + +new Proxy(p, {}); +new Proxy({}, p); + +r2.revoke(); + +new Proxy(p, {}); +new Proxy({}, p); + +r.revoke(); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + + +var g = newGlobal(); +p = g.eval(`var r = Proxy.revocable({}, {}); r.proxy;`); + +new Proxy(p, {}); +new Proxy({}, p); + +g.eval(`r.revoke();`); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index c8585dc3c80..3fee94cbe14 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 273; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 274; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 391, +static_assert(JSErr_Limit == 392, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "