From 63e44a7975868edc0a4c8c7e710670e718bd664c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 19 Oct 2014 01:18:43 -0700 Subject: [PATCH] Bug 1085566 - Make the preventExtensions hook return succeeded/failed rather than always indicate failure by reporting an error. r=efaust --HG-- extra : rebase_source : 487b569d23ce18f39fc53697e5f25cc789885803 --- dom/base/WindowNamedPropertiesHandler.h | 9 ++--- dom/base/nsGlobalWindow.cpp | 11 +++--- dom/bindings/DOMJSProxyHandler.cpp | 9 ++--- dom/bindings/DOMJSProxyHandler.h | 3 +- js/ipc/JavaScriptBase.h | 11 ++++-- js/ipc/PJavaScript.ipdl | 2 +- js/ipc/WrapperAnswer.cpp | 7 +++- js/ipc/WrapperAnswer.h | 3 +- js/ipc/WrapperOwner.cpp | 10 ++--- js/ipc/WrapperOwner.h | 5 ++- js/src/builtin/Object.cpp | 17 +++++++-- js/src/jsapi.cpp | 4 +- js/src/jsapi.h | 2 +- js/src/jsfun.cpp | 9 ++++- js/src/jsobj.cpp | 7 +++- js/src/jsobj.h | 7 ++-- js/src/jsproxy.h | 4 +- js/src/jswrapper.h | 4 +- js/src/proxy/CrossCompartmentWrapper.cpp | 5 ++- js/src/proxy/DeadObjectProxy.cpp | 2 +- js/src/proxy/DeadObjectProxy.h | 2 +- js/src/proxy/DirectProxyHandler.cpp | 4 +- js/src/proxy/Proxy.cpp | 4 +- js/src/proxy/Proxy.h | 2 +- js/src/proxy/ScriptedDirectProxyHandler.cpp | 38 +++++++++---------- js/src/proxy/ScriptedDirectProxyHandler.h | 2 +- js/src/proxy/ScriptedIndirectProxyHandler.cpp | 6 +-- js/src/proxy/ScriptedIndirectProxyHandler.h | 2 +- js/src/proxy/SecurityWrapper.cpp | 7 ++-- js/src/vm/Debugger.cpp | 9 ++++- js/src/vm/ScopeObject.cpp | 6 +-- js/src/vm/Shape.cpp | 9 +++-- js/xpconnect/wrappers/XrayWrapper.cpp | 7 ++-- js/xpconnect/wrappers/XrayWrapper.h | 2 +- 34 files changed, 136 insertions(+), 95 deletions(-) diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index 2b7f71c6df5..770aa9b23dc 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -20,12 +20,11 @@ public: { } virtual bool - preventExtensions(JSContext* aCx, JS::Handle aProxy) const MOZ_OVERRIDE + preventExtensions(JSContext* aCx, JS::Handle aProxy, + bool *succeeded) const MOZ_OVERRIDE { - // Throw a TypeError, per WebIDL. - JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, - JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } virtual bool getOwnPropDescriptor(JSContext* aCx, JS::Handle aProxy, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 61039e7263c..7fc5977f855 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -623,7 +623,8 @@ public: virtual bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, - JS::Handle proxy) const MOZ_OVERRIDE; + JS::Handle proxy, + bool *succeeded) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, JS::Handle proxy, JS::Handle id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle proxy, @@ -719,12 +720,12 @@ nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle proxy, bool nsOuterWindowProxy::preventExtensions(JSContext *cx, - JS::Handle proxy) const + JS::Handle proxy, + bool *succeeded) const { // See above. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, - JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } const char * diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index e0dd28caa8d..df9bbb38f0e 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -149,12 +149,11 @@ DOMProxyHandler::isExtensible(JSContext *cx, JS::Handle proxy, bool * } bool -DOMProxyHandler::preventExtensions(JSContext *cx, JS::Handle proxy) const +DOMProxyHandler::preventExtensions(JSContext *cx, JS::Handle proxy, + bool *succeeded) const { - // Throw a TypeError, per WebIDL. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, - JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } bool diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 7aa264b9e41..ac29e65ae21 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -117,7 +117,8 @@ public: JS::Handle id, bool* bp) const MOZ_OVERRIDE; bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible) const MOZ_OVERRIDE; - bool preventExtensions(JSContext *cx, JS::Handle proxy) const MOZ_OVERRIDE; + bool preventExtensions(JSContext *cx, JS::Handle proxy, + bool *succeeded) const MOZ_OVERRIDE; bool has(JSContext* cx, JS::Handle proxy, JS::Handle id, bool* bp) const MOZ_OVERRIDE; bool set(JSContext *cx, JS::Handle proxy, JS::Handle receiver, diff --git a/js/ipc/JavaScriptBase.h b/js/ipc/JavaScriptBase.h index a7cf7ff46ee..a80e784f3af 100644 --- a/js/ipc/JavaScriptBase.h +++ b/js/ipc/JavaScriptBase.h @@ -35,8 +35,10 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base /*** IPC handlers ***/ - bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs) { - return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs); + bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs, + bool *succeeded) { + return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs, + succeeded); } bool RecvGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id, ReturnStatus *rs, @@ -131,8 +133,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base bool SendDropObject(const ObjectId &objId) { return Base::SendDropObject(objId.serialize()); } - bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) { - return Base::SendPreventExtensions(objId.serialize(), rs); + bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs, + bool *succeeded) { + return Base::SendPreventExtensions(objId.serialize(), rs, succeeded); } bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs, diff --git a/js/ipc/PJavaScript.ipdl b/js/ipc/PJavaScript.ipdl index d8d0254e97e..6638ce19f3b 100644 --- a/js/ipc/PJavaScript.ipdl +++ b/js/ipc/PJavaScript.ipdl @@ -24,7 +24,7 @@ both: async DropObject(uint64_t objId); // These roughly map to the ProxyHandler hooks that CPOWs need. - prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs); + prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs, bool result); prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result); prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result); prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs); diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp index 6f80222da24..40e316bf0dc 100644 --- a/js/ipc/WrapperAnswer.cpp +++ b/js/ipc/WrapperAnswer.cpp @@ -58,17 +58,20 @@ WrapperAnswer::ok(ReturnStatus *rs) } bool -WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs) +WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs, + bool *succeeded) { AutoSafeJSContext cx; JSAutoRequest request(cx); + *succeeded = false; + RootedObject obj(cx, findObjectById(cx, objId)); if (!obj) return fail(cx, rs); JSAutoCompartment comp(cx, obj); - if (!JS_PreventExtensions(cx, obj)) + if (!JS_PreventExtensions(cx, obj, succeeded)) return fail(cx, rs); LOG("%s.preventExtensions()", ReceiverObj(objId)); diff --git a/js/ipc/WrapperAnswer.h b/js/ipc/WrapperAnswer.h index 08171528de2..180bad5abaa 100644 --- a/js/ipc/WrapperAnswer.h +++ b/js/ipc/WrapperAnswer.h @@ -18,7 +18,8 @@ class WrapperAnswer : public virtual JavaScriptShared public: explicit WrapperAnswer(JSRuntime *rt) : JavaScriptShared(rt) {} - bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs); + bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs, + bool *succeeded); bool RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs, PPropertyDescriptor *out); diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index fb5767420ac..6339a32b45a 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -72,7 +72,7 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE; @@ -113,18 +113,18 @@ const CPOWProxyHandler CPOWProxyHandler::singleton; return owner->call args; bool -CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const +CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const { - FORWARD(preventExtensions, (cx, proxy)); + FORWARD(preventExtensions, (cx, proxy, succeeded)); } bool -WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy) +WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) { ObjectId objId = idOf(proxy); ReturnStatus status; - if (!SendPreventExtensions(objId, &status)) + if (!SendPreventExtensions(objId, &status, succeeded)) return ipcfail(cx); LOG_STACK(); diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index a626ca1832a..60883baf646 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -41,7 +41,7 @@ class WrapperOwner : public virtual JavaScriptShared bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp); bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props); bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible); - bool preventExtensions(JSContext *cx, JS::HandleObject proxy); + bool preventExtensions(JSContext *cx, JS::HandleObject proxy, bool *succeeded); bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp); bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver, JS::HandleId id, JS::MutableHandleValue vp); @@ -106,7 +106,8 @@ class WrapperOwner : public virtual JavaScriptShared /*** Dummy call handlers ***/ public: virtual bool SendDropObject(const ObjectId &objId) = 0; - virtual bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) = 0; + virtual bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs, + bool *succeeded) = 0; virtual bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs, PPropertyDescriptor *out) = 0; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 5f9e7b40e04..5674de0eadd 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1012,7 +1012,7 @@ obj_isExtensible(JSContext *cx, unsigned argc, Value *vp) return true; } -// ES6 draft rev27 (2014/08/24) 19.1.2.15 Object.preventExtensions(O) +// ES6 20141014 draft 19.1.2.15 Object.preventExtensions(O) static bool obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp) { @@ -1023,10 +1023,21 @@ obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp) if (!args.get(0).isObject()) return true; - // Steps 2-5. + // Steps 2-3. RootedObject obj(cx, &args.get(0).toObject()); - return JSObject::preventExtensions(cx, obj); + bool status; + if (!JSObject::preventExtensions(cx, obj, &status)) + return false; + + // Step 4. + if (!status) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return false; + } + + // Step 5. + return true; } // ES6 draft rev27 (2014/08/24) 19.1.2.5 Object.freeze(O) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d6921e896e2..01bd6a705cc 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6458,9 +6458,9 @@ JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length) } JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext *cx, JS::HandleObject obj) +JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded) { - return JSObject::preventExtensions(cx, obj); + return JSObject::preventExtensions(cx, obj, succeeded); } JS_PUBLIC_API(void) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 34b2e3f9d2f..d92e652fc3c 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2795,7 +2795,7 @@ extern JS_PUBLIC_API(bool) JS_FreezeObject(JSContext *cx, JS::Handle obj); extern JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext *cx, JS::HandleObject obj); +JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded); extern JS_PUBLIC_API(JSObject *) JS_New(JSContext *cx, JS::HandleObject ctor, const JS::HandleValueArray& args); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 76f6db09c5f..f695bca6e80 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -868,10 +868,17 @@ CreateFunctionPrototype(JSContext *cx, JSProtoKey key) SingletonObject)); if (!tte) return nullptr; + + bool succeeded; RootedFunction throwTypeError(cx, NewFunction(cx, tte, ThrowTypeError, 0, JSFunction::NATIVE_FUN, self, js::NullPtr())); - if (!throwTypeError || !JSObject::preventExtensions(cx, throwTypeError)) + if (!throwTypeError || !JSObject::preventExtensions(cx, throwTypeError, &succeeded)) return nullptr; + if (!succeeded) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return nullptr; + } + self->setThrowTypeError(throwTypeError); return functionProto; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 55559dd9d75..e900df80f85 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1229,8 +1229,13 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it) assertSameCompartment(cx, obj); MOZ_ASSERT(it == SEAL || it == FREEZE); - if (!JSObject::preventExtensions(cx, obj)) + bool succeeded; + if (!JSObject::preventExtensions(cx, obj, &succeeded)) return false; + if (!succeeded) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return false; + } AutoIdVector props(cx); if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &props)) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 755cf8e8eb4..eacceebb516 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -514,10 +514,11 @@ class JSObject : public js::gc::Cell return !lastProperty()->hasObjectFlag(js::BaseShape::NOT_EXTENSIBLE); } - // Attempt to change the [[Extensible]] bit on |obj| to false. Callers - // must ensure that |obj| is currently extensible before calling this! + // Attempt to change the [[Extensible]] bit on |obj| to false. Indicate + // success or failure through the |*succeeded| outparam, or actual error + // through the return value. static bool - preventExtensions(JSContext *cx, js::HandleObject obj); + preventExtensions(JSContext *cx, js::HandleObject obj, bool *succeeded); private: enum ImmutabilityType { SEAL, FREEZE }; diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index f06bda5f2f8..ab2e7008daf 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -257,7 +257,7 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const = 0; /* * These methods are standard, but the engine does not normally call them. @@ -369,7 +369,7 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 42073d30ac9..edaf23d5231 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -123,7 +123,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, @@ -185,7 +185,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const MOZ_OVERRIDE; virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index d145d05c270..2b5932b5347 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -37,11 +37,12 @@ CrossCompartmentWrapper::isExtensible(JSContext *cx, HandleObject wrapper, bool } bool -CrossCompartmentWrapper::preventExtensions(JSContext *cx, HandleObject wrapper) const +CrossCompartmentWrapper::preventExtensions(JSContext *cx, HandleObject wrapper, + bool *succeeded) const { PIERCE(cx, wrapper, NOTHING, - Wrapper::preventExtensions(cx, wrapper), + Wrapper::preventExtensions(cx, wrapper, succeeded), NOTHING); } diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index d6b15e2b69e..ba3d8000212 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -24,7 +24,7 @@ DeadObjectProxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensibl } bool -DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy) const +DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); return false; diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index dbd574fb4a0..fb0fa52b2c9 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -28,7 +28,7 @@ class DeadObjectProxy : public BaseProxyHandler virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index 77ed6a1de82..5e6bddd459c 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -251,10 +251,10 @@ DirectProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extens } bool -DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const +DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const { RootedObject target(cx, proxy->as().target()); - return JSObject::preventExtensions(cx, target); + return JSObject::preventExtensions(cx, target, succeeded); } bool diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index f4fe92252ca..8ae764154dc 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -387,11 +387,11 @@ Proxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) } bool -Proxy::preventExtensions(JSContext *cx, HandleObject proxy) +Proxy::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); - return handler->preventExtensions(cx, proxy); + return handler->preventExtensions(cx, proxy, succeeded); } bool diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 36931024365..f163c52cda6 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -36,7 +36,7 @@ class Proxy static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props); static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); - static bool preventExtensions(JSContext *cx, HandleObject proxy); + static bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded); static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); static bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 4ce6bced611..4734f877f86 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -273,32 +273,31 @@ ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleVa return true; } -// ES6 (22 May, 2014) 9.5.4 Proxy.[[PreventExtensions]]() +// ES6 20141014 9.5.4 Proxy.[[PreventExtensions]]() bool -ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const +ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, + bool *succeeded) const { - // step 1 + // Steps 1-3. RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); - - // step 2 if (!handler) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } - // step 3 + // Step 4. RootedObject target(cx, proxy->as().target()); - // step 4-5 + // Steps 5-6. RootedValue trap(cx); if (!JSObject::getProperty(cx, handler, handler, cx->names().preventExtensions, &trap)) return false; - // step 6 + // Step 7. if (trap.isUndefined()) - return DirectProxyHandler::preventExtensions(cx, proxy); + return DirectProxyHandler::preventExtensions(cx, proxy, succeeded); - // step 7, 9 + // Steps 8, 10. Value argv[] = { ObjectValue(*target) }; @@ -306,10 +305,11 @@ ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; - // step 8 - bool success = ToBoolean(trapResult); - if (success) { - // step 10 + // Step 9. + bool booleanTrapResult = ToBoolean(trapResult); + + // Step 11. + if (booleanTrapResult) { bool extensible; if (!JSObject::isExtensible(cx, target, &extensible)) return false; @@ -317,15 +317,11 @@ ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE); return false; } - // step 11 "return true" - return true; } - // step 11 "return false" - // This actually corresponds to 19.1.2.5 step 4. We cannot pass the failure back, so throw here - // directly instead. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + // Step 12. + *succeeded = booleanTrapResult; + return true; } // ES6 implements both getPrototypeOf and setPrototypeOf traps. We don't have them yet (see bug diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index 0c1d00bb761..f171e8c6b3c 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -28,7 +28,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; /* These two are standard internal methods but aren't implemented to spec yet. */ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index cc3c4aeda1c..28be88d329e 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -140,11 +140,11 @@ ScriptedIndirectProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, } bool -ScriptedIndirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const +ScriptedIndirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const { // See above. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } static bool diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index 1f51499e48e..3f1be364de8 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -29,7 +29,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE; diff --git a/js/src/proxy/SecurityWrapper.cpp b/js/src/proxy/SecurityWrapper.cpp index 1a4ba552cbb..0a7831844bc 100644 --- a/js/src/proxy/SecurityWrapper.cpp +++ b/js/src/proxy/SecurityWrapper.cpp @@ -24,11 +24,12 @@ SecurityWrapper::isExtensible(JSContext *cx, HandleObject wrapper, bool *e template bool -SecurityWrapper::preventExtensions(JSContext *cx, HandleObject wrapper) const +SecurityWrapper::preventExtensions(JSContext *cx, HandleObject wrapper, + bool *succeeded) const { // See above. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED); - return false; + *succeeded = false; + return true; } template diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 92d13d051d6..c55f864f1b3 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -5863,7 +5863,14 @@ DebuggerObject_sealHelper(JSContext *cx, unsigned argc, Value *vp, SealHelperOp ok = JSObject::freeze(cx, obj); } else { MOZ_ASSERT(op == PreventExtensions); - ok = JSObject::preventExtensions(cx, obj); + bool succeeded; + ok = JSObject::preventExtensions(cx, obj, &succeeded); + if (!ok) + return false; + if (!succeeded) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return false; + } } if (!ok) return false; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 49ef141960b..da9b7670cb3 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1513,11 +1513,11 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE + bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE { // See above. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index a2ca9a922eb..93bd7bf65db 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1345,13 +1345,15 @@ Shape::setObjectMetadata(JSContext *cx, JSObject *metadata, TaggedProto proto, S } /* static */ bool -JSObject::preventExtensions(JSContext *cx, HandleObject obj) +JSObject::preventExtensions(JSContext *cx, HandleObject obj, bool *succeeded) { if (obj->is()) - return js::Proxy::preventExtensions(cx, obj); + return js::Proxy::preventExtensions(cx, obj, succeeded); - if (!obj->nonProxyIsExtensible()) + if (!obj->nonProxyIsExtensible()) { + *succeeded = true; return true; + } /* * Force lazy properties to be resolved by iterating over the objects' own @@ -1370,6 +1372,7 @@ JSObject::preventExtensions(JSContext *cx, HandleObject obj) if (obj->isNative() && !NativeObject::sparsifyDenseElements(cx, obj.as())) return false; + *succeeded = true; return obj->setFlag(cx, BaseShape::NOT_EXTENSIBLE, GENERATE_SHAPE); } diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index f0582112f46..962de7f05e9 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1759,11 +1759,12 @@ XrayWrapper::isExtensible(JSContext *cx, JS::Handle wra template bool -XrayWrapper::preventExtensions(JSContext *cx, HandleObject wrapper) const +XrayWrapper::preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) + const { // See above. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY); - return false; + *succeeded = false; + return true; } template diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 6f0ef20a173..4f0febeb85f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -415,7 +415,7 @@ class XrayWrapper : public Base { JS::Handle id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, JS::Handle wrapper, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, JS::Handle wrapper) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, JS::Handle wrapper, bool *succeeded) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper, JS::MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,