From 02c638ea3613450fc34f88edcd1f7f5734e05014 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 19 Jun 2014 09:57:06 -0700 Subject: [PATCH] Bug 976148 - Implement Xrays to Function objects. r=gabor --- js/xpconnect/tests/chrome/test_bug448587.xul | 5 +++-- js/xpconnect/tests/chrome/test_bug812415.xul | 2 +- js/xpconnect/tests/chrome/test_xrayToJS.xul | 5 +++-- js/xpconnect/wrappers/WrapperFactory.cpp | 19 ++++++++++--------- js/xpconnect/wrappers/XrayWrapper.cpp | 18 ++++++++++++++++-- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/js/xpconnect/tests/chrome/test_bug448587.xul b/js/xpconnect/tests/chrome/test_bug448587.xul index 1b173556d2ad..98ee5dedaef9 100644 --- a/js/xpconnect/tests/chrome/test_bug448587.xul +++ b/js/xpconnect/tests/chrome/test_bug448587.xul @@ -29,8 +29,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448587.xul const Cu = Components.utils; var sandbox = new Cu.Sandbox("about:blank"); var fwrapper = Cu.evalInSandbox("function f() {} f", sandbox); - is(fwrapper.prototype, Cu.evalInSandbox("f.prototype", sandbox), - "we don't censor .prototype through .wrappedJSObject"); + is(Cu.unwaiveXrays(Cu.waiveXrays(fwrapper).prototype), Cu.evalInSandbox("f.prototype", sandbox), + ".prototype visible through .wrappedJSObject"); + is(fwrapper.prototype, undefined, ".prototype invisible through Xrays"); ]]> diff --git a/js/xpconnect/tests/chrome/test_bug812415.xul b/js/xpconnect/tests/chrome/test_bug812415.xul index b3d370882e4d..5afff4214b62 100644 --- a/js/xpconnect/tests/chrome/test_bug812415.xul +++ b/js/xpconnect/tests/chrome/test_bug812415.xul @@ -56,7 +56,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=812415 is(Cu.evalInSandbox('regFun.name', expanded), 'reg', "Expanded can see regular function's name"); checkThrows('expFun.name', regular, "Regular can't see expanded function's name"); Cu.evalInSandbox('regFun.expando = 30', expanded); - is(expanded.regFun.expando, 30, "Expanded can set expandos"); + is(Cu.evalInSandbox('regFun.expando', expanded), 30, "Expanded can set expandos"); checkThrows('expFun.expando = 29', regular, "Regular can't set expandos"); // Check __proto__ stuff. diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 65877e6ef6ba..f615c388267c 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -65,7 +65,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 is(global(num), iwin, "correct global for num"); var obj = new iwin.Object(); obj.foo = 2; - var withProto = iwin.Object.create(obj); + var withProto = Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(obj)); is(global(withProto), iwin, "correct global for withProto"); is(Cu.waiveXrays(withProto).foo, 2, "Inherits properly"); @@ -242,7 +242,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 } function testObject() { - testXray('Object', iwin.Object.create(new iwin.Object()), new iwin.Object(), []); + testXray('Object', Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(new iwin.Object())), + new iwin.Object(), []); // Construct an object full of tricky things. var trickyObject = diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 3a3b8d9df04c..f1d1e67da55d 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -128,9 +128,9 @@ static bool ForceCOWBehavior(JSObject *obj) { JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj); - if (key == JSProto_Object || key == JSProto_Array) { + if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) { MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject, - "We should use XrayWrappers for standard ES Object and Array " + "We should use XrayWrappers for standard ES Object, Array, and Function " "instances modulo this hack"); return true; } @@ -360,13 +360,6 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, if (!wantXrays || xrayType == NotXray) { if (!securityWrapper) return &CrossCompartmentWrapper::singleton; - // In general, we don't want opaque function wrappers to be callable. - // But in the case of XBL, we rely on content being able to invoke - // functions exposed from the XBL scope. We could remove this exception, - // if needed, by using ExportFunction to generate the content-side - // representations of XBL methods. - else if (originIsXBLScope) - return &FilteringWrapper::singleton; return &FilteringWrapper::singleton; } @@ -390,7 +383,15 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, CrossOriginAccessiblePropertiesOnly>::singleton; // There's never any reason to expose pure JS objects to non-subsuming actors. // Just use an opaque wrapper in this case. + // + // In general, we don't want opaque function wrappers to be callable. + // But in the case of XBL, we rely on content being able to invoke + // functions exposed from the XBL scope. We could remove this exception, + // if needed, by using ExportFunction to generate the content-side + // representations of XBL methods. MOZ_ASSERT(xrayType == XrayForJSObject); + if (originIsXBLScope) + return &FilteringWrapper::singleton; return &FilteringWrapper::singleton; } diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index e5894b3e51e4..6688ad276c1f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -71,6 +71,7 @@ IsJSXraySupported(JSProtoKey key) case JSProto_Date: case JSProto_Object: case JSProto_Array: + case JSProto_Function: return true; default: return false; @@ -171,6 +172,8 @@ public: class XrayTraits { public: + XrayTraits() {} + static JSObject* getTargetObject(JSObject *wrapper) { return js::UncheckedUnwrap(wrapper, /* stopAtOuter = */ false); } @@ -224,6 +227,9 @@ private: JSObject* attachExpandoObject(JSContext *cx, HandleObject target, nsIPrincipal *origin, HandleObject exclusiveGlobal); + + XrayTraits(XrayTraits &) MOZ_DELETE; + const XrayTraits& operator=(XrayTraits &) MOZ_DELETE; }; class XPCWrappedNativeXrayTraits : public XrayTraits @@ -349,7 +355,11 @@ public: static bool call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args, js::Wrapper& baseInstance) { - // We'll handle this when we start supporting Functions. + JSXrayTraits &self = JSXrayTraits::singleton; + RootedObject holder(cx, self.ensureHolder(cx, wrapper)); + if (self.getProtoKey(holder) == JSProto_Function) + return baseInstance.call(cx, wrapper, args); + RootedValue v(cx, ObjectValue(*wrapper)); js_ReportIsNotFunction(cx, v); return false; @@ -358,7 +368,11 @@ public: static bool construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args, js::Wrapper& baseInstance) { - // We'll handle this when we start supporting Functions. + JSXrayTraits &self = JSXrayTraits::singleton; + RootedObject holder(cx, self.ensureHolder(cx, wrapper)); + if (self.getProtoKey(holder) == JSProto_Function) + return baseInstance.construct(cx, wrapper, args); + RootedValue v(cx, ObjectValue(*wrapper)); js_ReportIsNotFunction(cx, v); return false;