Backed out 6 changesets (bug 843829, bug 845862) because of broken mochitest-5
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 02 Apr 2013 23:05:48 -0400
changeset 127137 e60919ded783
parent 127136 84588077a188
child 127138 3a5929ebc886
push id117
push usertomi.aarnio@nokia.com
push dateWed, 03 Apr 2013 12:07:07 +0000
bugs843829, 845862
milestone23.0a1
backs out1df3bdadb7ce
64f001fe04fb
57652d8f0827
2e889cd77a48
97d16e7beb27
6c6ab0e54917
Backed out 6 changesets (bug 843829, bug 845862) because of broken mochitest-5 Backed out changeset 1df3bdadb7ce (bug 843829) Backed out changeset 64f001fe04fb (bug 843829) Backed out changeset 57652d8f0827 (bug 843829) Backed out changeset 2e889cd77a48 (bug 843829) Backed out changeset 97d16e7beb27 (bug 843829) Backed out changeset 6c6ab0e54917 (bug 845862) Landed on a CLOSED TREE
content/xbl/src/nsXBLProtoImplField.cpp
content/xbl/test/file_bug821850.xhtml
js/xpconnect/tests/unit/test_bug845862.js
js/xpconnect/tests/unit/xpcshell.ini
js/xpconnect/wrappers/AccessCheck.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/Makefile.in
js/xpconnect/wrappers/WaiveXrayWrapper.cpp
js/xpconnect/wrappers/WaiveXrayWrapper.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -12,17 +12,16 @@
 #include "nsReadableUtils.h"
 #include "nsXBLProtoImplField.h"
 #include "nsIScriptContext.h"
 #include "nsIURI.h"
 #include "nsXBLSerialize.h"
 #include "nsXBLPrototypeBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "xpcpublic.h"
-#include "WrapperFactory.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsXBLProtoImplField::nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly)
   : mNext(nullptr),
     mFieldText(nullptr),
     mFieldTextLength(0),
@@ -247,46 +246,18 @@ FieldGetterImpl(JSContext *cx, JS::CallA
   }
   args.rval().set(v);
   return true;
 }
 
 static JSBool
 FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
 {
-  // FieldGetter generally lives in the XBL scope, and is defined as a cross-
-  // compartment wrapper on the in-content XBL prototype object. When content
-  // accesses the field for the first time, it ends up invoking the wrapped
-  // FieldGetter on the prototype, which enters the XBL scope, landing us here.
-  // We then use the nativeCall machinery to re-enter the content compartment
-  // (unwrapping |this|), define the field on the in-content |this|, and return
-  // the value of the field to the caller.
-  //
-  // There's one hitch, though. When code in the XBL scope accesses a field on
-  // the content object, we waive the usual Xray vision granted to XBL scopes
-  // in order to do the access, because there isn't really anything else sane to
-  // do. In this sequence of events, the chrome caller invokes a get() for the
-  // field on the Xrayed element. XrayWrapper::get bounces to BaseProxyHandler::get,
-  // Which invokes XrayWrapper::getPropertyDescriptor. This detects the field
-  // access, creates a waived version of the wrapper, and does a lookup for the
-  // property on the waived wrapper. This would normally result in the resulting
-  // getter being transitively waived, which would cause said getter to properly
-  // waive Xray on its return value when it is eventually invoked (by the XBL
-  // scope) further down in BaseProxyHandler::get. However, this getter is
-  // FieldGetter, which actually lives in the XBL scope, meaning that we end up
-  // stripping all the wrappers off, effectively losing track of the fact that
-  // we meant to be waiving Xray here.
-  //
-  // Since fields are already doing this special Xray waiving stuff, the simplest
-  // solution seems to be to waive Xray on the |this| object before invoking
-  // CallNonGenericMethod. This means that the nativeCall trap of WaiveXrayWrapper
-  // will properly waive the result on the way back. Whew.
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-  return xpc::WrapperFactory::WaiveXrayAndWrap(cx, args.mutableThisv().address()) &&
-         JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldGetterImpl>
+  return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldGetterImpl>
                                  (cx, args);
 }
 
 bool
 FieldSetterImpl(JSContext *cx, JS::CallArgs args)
 {
   const JS::Value &thisv = args.thisv();
   MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
@@ -315,22 +286,17 @@ FieldSetterImpl(JSContext *cx, JS::CallA
   args.rval().setUndefined();
   return true;
 }
 
 static JSBool
 FieldSetter(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-  // It's probably not actually necessary to waive Xray here given that
-  // FieldSetter doesn't return everything, but it's good to maintain
-  // consistency with FieldGetter. See the comment there for more details on
-  // why we do this.
-  return xpc::WrapperFactory::WaiveXrayAndWrap(cx, args.mutableThisv().address()) &&
-         JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldSetterImpl>
+  return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldSetterImpl>
                                  (cx, args);
 }
 
 nsresult
 nsXBLProtoImplField::InstallAccessors(JSContext* aCx,
                                       JSObject* aTargetClassObject)
 {
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
--- a/content/xbl/test/file_bug821850.xhtml
+++ b/content/xbl/test/file_bug821850.xhtml
@@ -39,18 +39,18 @@ https://bugzilla.mozilla.org/show_bug.cg
           var bound = document.getElementById('bound');
           ok(bound, "bound is non-null");
           is(bound.method('baz'), "method:baz", "Xray methods work");
           is(bound.prop, "propVal", "Property Xrays work");
           is(bound.primitiveField, 2, "Field Xrays work");
           is(bound.objectField.bar.a, 1, "Field Xrays work on objects");
           is(bound.contentField.foo, 10, "Field Xrays work on content objects");
           var hole = bound.contentField.rabbit.hole;
-          ok(hole.win === XPCNativeWrapper.unwrap(window), "Xray vision remains waived when hitting a native object");
-          ok(!Cu.isXrayWrapper(hole.win), "Xray is waived");
+          is(hole.win, window, "We gain back Xray vision when hitting a native object");
+          ok(Cu.isXrayWrapper(hole.win), "Really is Xray");
 
           // This gets invoked by an event handler.
           window.finish = function() {
             // Content messed with stuff. Make sure we still see the right thing.
             is(bound.method('bay'), "method:bay", "Xray methods work");
             is(bound.wrappedJSObject.method('bay'), "hah", "Xray waived methods work");
             is(bound.prop, "set:someOtherVal", "Xray props work");
             is(bound.wrappedJSObject.prop, "redefined", "Xray waived props work");
@@ -66,30 +66,16 @@ https://bugzilla.mozilla.org/show_bug.cg
         <field name="objectField">({ foo: 2, bar: {a: 1} })</field>
         <field name="contentField">XPCNativeWrapper.unwrap(window).contentVal</field>
         <method name="method">
           <parameter name="arg" />
           <body>
             return "method:" + arg;
           </body>
         </method>
-        <method name="passMeAJSObject">
-          <parameter name="arg" />
-          <body>
-            is(typeof arg.prop, 'undefined', "No properties");
-            is(Object.getOwnPropertyNames(arg).length, 0, "Should have no own properties");
-            try {
-              arg.foo = 2;
-              ok(true, "Stuff fails silently");
-            } catch (e) {
-              ok(false, "Stuff should fail silently");
-            }
-            is(typeof arg.foo, 'undefined', "Shouldn't place props");
-          </body>
-        </method>
         <property name="prop">
           <getter>return this._prop;</getter>
           <setter>this._prop = "set:" + val;</setter>
         </property>
       </implementation>
       <handlers>
         <handler event="testevent" action="ok(true, 'called event handler'); finish();"/>
       </handlers>
@@ -129,24 +115,21 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(bound.primitiveField, 2, "Can see primitive fields");
     is(typeof bound.objectField, "object", "objectField exists");
     checkThrows(function() bound.objectField.foo);
     is(bound.method("foo"), "method:foo", "Can invoke XBL method from content");
     is(bound.prop, "propVal", "Can access properties from content");
     bound.prop = "someOtherVal";
     is(bound.prop, "set:someOtherVal", "Can set properties from content");
 
-    // Make sure we can't pass JS objects to the XBL scope.
-    var proto = bound.__proto__;
-    proto.passMeAJSObject({prop: 2});
-
     //
     // Try sticking a bunch of stuff on the prototype object.
     //
 
+    var proto = bound.__proto__;
     proto.someExpando = 201;
     is(bound.someExpando, 201, "Can stick non-XBL properties on the proto");
 
     // Previously, this code checked that content couldn't tamper with its XBL
     // prototype. But we decided to allow this to reduce regression risk, so for
     // now just check that this works.
     function checkMayTamper(obj, propName, desc) {
       var accessor = !('value' in Object.getOwnPropertyDescriptor(obj, propName));
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_bug845862.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const Cu = Components.utils;
-
-function run_test() {
-  // We rely on the crazy "wantXrays:false also causes values return from the
-  // sandbox to be waived" behavior, because it's the simplest way to get
-  // waivers out of the sandbox (which has no native objects). :-(
-  var sb = new Cu.Sandbox('http://www.example.com', {wantXrays: false});
-  Cu.evalInSandbox("this.foo = {}; Object.defineProperty(foo, 'bar', {get: function() {return {};}});", sb);
-  do_check_true(sb.foo != XPCNativeWrapper(sb.foo), "sb.foo is waived");
-  var desc = Object.getOwnPropertyDescriptor(sb.foo, 'bar');
-  var b = desc.get();
-  do_check_true(b != XPCNativeWrapper(b), "results from accessor descriptors are waived");
-}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -12,17 +12,16 @@ tail =
 [test_bug677864.js]
 [test_bug711404.js]
 [test_bug778409.js]
 [test_bug780370.js]
 [test_bug805807.js]
 [test_bug809652.js]
 [test_bug813901.js]
 [test_bug845201.js]
-[test_bug845862.js]
 [test_bug849730.js]
 [test_bug851895.js]
 [test_bug854558.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_blob.js]
 [test_import.js]
 [test_import_fail.js]
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -48,40 +48,16 @@ struct Opaque : public Policy {
     {
         return false;
     }
     static bool isSafeToUnwrap() {
         return false;
     }
 };
 
-// This policy is designed to protect privileged callers from untrusted non-
-// Xrayable objects. Nothing is allowed, and nothing throws.
-struct GentlyOpaque : public Policy {
-    static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
-        return false;
-    }
-    static bool deny(js::Wrapper::Action act) {
-        return true;
-    }
-    static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl)
-    {
-        // We allow nativeCall here because the alternative is throwing (which
-        // happens in SecurityWrapper::nativeCall), which we don't want. There's
-        // unlikely to be too much harm to letting this through, because this
-        // wrapper is only used to wrap less-privileged objects in more-privileged
-        // scopes, so unwrapping here only drops privileges.
-        return true;
-    }
-
-    static bool isSafeToUnwrap() {
-        return false;
-    }
-};
-
 // This policy only permits access to the object if the subject can touch
 // system objects.
 struct OnlyIfSubjectIsSystem : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
         return AccessCheck::isSystemOnlyAccessPermitted(cx);
     }
 
     static bool deny(js::Wrapper::Action act) {
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -140,40 +140,16 @@ FilteringWrapper<Base, Policy>::nativeCa
 {
     if (Policy::allowNativeCall(cx, test, impl))
         return Base::Permissive::nativeCall(cx, test, impl, args);
     return Base::Restrictive::nativeCall(cx, test, impl, args);
 }
 
 template <typename Base, typename Policy>
 bool
-FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
-                                             JSType hint, MutableHandleValue vp)
-{
-    return Base::defaultValue(cx, obj, hint, vp);
-}
-
-// With our entirely-opaque wrapper, the DefaultValue algorithm throws,
-// causing spurious exceptions. Manually implement something benign.
-template<>
-bool
-FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
-                ::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
-                               JSType hint, MutableHandleValue vp)
-{
-    JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
-    if (!str)
-        return false;
-    vp.set(JS::StringValue(str));
-    return true;
-}
-
-
-template <typename Base, typename Policy>
-bool
 FilteringWrapper<Base, Policy>::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                       JS::Handle<jsid> id, Wrapper::Action act, bool *bp)
 {
     // This is a super ugly hacky to get around Xray Resolve wonkiness.
     //
     // Basically, XPCWN Xrays sometimes call into the Resolve hook of the
     // scriptable helper, and pass the wrapper itself as the object upon which
     // the resolve is happening. Then, special handling happens in
@@ -198,27 +174,23 @@ FilteringWrapper<Base, Policy>::enter(JS
 
 #define SOW FilteringWrapper<CrossCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
 #define SCSOW FilteringWrapper<SameCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
 #define XOW FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>
 #define DXOW   FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>
 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
 #define CW FilteringWrapper<SameCompartmentSecurityWrapper, ComponentsObjectPolicy>
 #define XCW FilteringWrapper<CrossCompartmentSecurityWrapper, ComponentsObjectPolicy>
-#define GO FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
 template<> SOW SOW::singleton(WrapperFactory::SOW_FLAG);
 template<> SCSOW SCSOW::singleton(WrapperFactory::SOW_FLAG);
 template<> XOW XOW::singleton(0);
 template<> DXOW DXOW::singleton(0);
 template<> NNXOW NNXOW::singleton(0);
 
 template<> CW CW::singleton(0);
 template<> XCW XCW::singleton(0);
 
-template<> GO GO::singleton(0);
-
 template class SOW;
 template class XOW;
 template class DXOW;
 template class NNXOW;
 template class ChromeObjectWrapperBase;
-template class GO;
 }
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -34,18 +34,16 @@ class FilteringWrapper : public Base {
                            js::AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool keys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       js::AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                          JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl,
                             JS::CallArgs args) MOZ_OVERRIDE;
 
-    virtual bool defaultValue(JSContext *cx, JS::Handle<JSObject*> obj, JSType hint, JS::MutableHandleValue vp) MOZ_OVERRIDE;
-
     virtual bool enter(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                        js::Wrapper::Action act, bool *bp) MOZ_OVERRIDE;
 
     static FilteringWrapper singleton;
 };
 
 }
 
--- a/js/xpconnect/wrappers/Makefile.in
+++ b/js/xpconnect/wrappers/Makefile.in
@@ -7,19 +7,16 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= xpcwrappers_s
 FORCE_STATIC_LIB = 1
 LIBXUL_LIBRARY = 1
-EXPORTS = \
-  WrapperFactory.h \
-  $(NULL)
 
 CPPSRCS = \
   AccessCheck.cpp \
   WaiveXrayWrapper.cpp \
   FilteringWrapper.cpp \
   ChromeObjectWrapper.cpp \
   XrayWrapper.cpp \
   WrapperFactory.cpp \
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
@@ -10,59 +10,40 @@
 #include "XPCWrapper.h"
 
 #include "WaiveXrayWrapper.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
 namespace xpc {
 
-static bool
-WaiveAccessors(JSContext *cx, js::PropertyDescriptor *desc)
-{
-    if ((desc->attrs & JSPROP_GETTER) && desc->getter) {
-        JS::Value v = JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
-        if (!WrapperFactory::WaiveXrayAndWrap(cx, &v))
-            return false;
-        desc->getter = js::CastAsJSPropertyOp(&v.toObject());
-    }
-
-    if ((desc->attrs & JSPROP_SETTER) && desc->setter) {
-        JS::Value v = JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
-        if (!WrapperFactory::WaiveXrayAndWrap(cx, &v))
-            return false;
-        desc->setter = js::CastAsJSStrictPropertyOp(&v.toObject());
-    }
-    return true;
-}
-
 WaiveXrayWrapper::WaiveXrayWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
 {
 }
 
 WaiveXrayWrapper::~WaiveXrayWrapper()
 {
 }
 
 bool
 WaiveXrayWrapper::getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*>wrapper,
                                         JS::Handle<jsid> id, js::PropertyDescriptor *desc,
                                         unsigned flags)
 {
     return CrossCompartmentWrapper::getPropertyDescriptor(cx, wrapper, id, desc, flags) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value) && WaiveAccessors(cx, desc);
+           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value);
 }
 
 bool
 WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                            JS::Handle<jsid> id, js::PropertyDescriptor *desc,
                                            unsigned flags)
 {
     return CrossCompartmentWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value) && WaiveAccessors(cx, desc);
+           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value);
 }
 
 bool
 WaiveXrayWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
                       JS::MutableHandle<JS::Value> vp)
 {
     return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&
@@ -80,19 +61,9 @@ WaiveXrayWrapper::call(JSContext *cx, JS
 bool
 WaiveXrayWrapper::construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                               unsigned argc, js::Value *argv, JS::MutableHandle<JS::Value> rval)
 {
     return CrossCompartmentWrapper::construct(cx, wrapper, argc, argv, rval) &&
            WrapperFactory::WaiveXrayAndWrap(cx, rval.address());
 }
 
-// NB: This is important as the other side of a handshake with FieldGetter. See
-// nsXBLProtoImplField.cpp.
-bool
-WaiveXrayWrapper::nativeCall(JSContext *cx, JS::IsAcceptableThis test,
-                             JS::NativeImpl impl, JS::CallArgs args)
-{
-    return CrossCompartmentWrapper::nativeCall(cx, test, impl, args) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, args.rval().address());
 }
-
-}
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.h
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h
@@ -31,17 +31,14 @@ class WaiveXrayWrapper : public js::Cros
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned argc,
                       js::Value *vp) MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            unsigned argc, js::Value *argv,
                            JS::MutableHandle<JS::Value> rval) MOZ_OVERRIDE;
 
-    virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test,
-                            JS::NativeImpl impl, JS::CallArgs args) MOZ_OVERRIDE;
-
     static WaiveXrayWrapper singleton;
 };
 
 }
 
 #endif
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -288,20 +288,16 @@ DEBUG_CheckUnwrapSafety(JSObject *obj, j
         MOZ_ASSERT(handler->isSafeToUnwrap());
     } else if (WrapperFactory::IsComponentsObject(obj))
     {
         // The Components object that is restricted regardless of origin.
         MOZ_ASSERT(!handler->isSafeToUnwrap());
     } else if (AccessCheck::needsSystemOnlyWrapper(obj)) {
         // SOWs have a dynamic unwrap check, so we can't really say anything useful
         // about them here :-(
-    } else if (handler == &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton) {
-        // We explicitly use a SecurityWrapper to protect privileged callers from
-        // less-privileged objects that they should never see. Skip the check in
-        // this case.
     } else {
         // Otherwise, it should depend on whether the target subsumes the origin.
         MOZ_ASSERT(handler->isSafeToUnwrap() == AccessCheck::subsumes(target, origin));
     }
 }
 #else
 #define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) {}
 #endif
@@ -360,17 +356,16 @@ WrapperFactory::Rewrap(JSContext *cx, JS
     JSCompartment *origin = js::GetObjectCompartment(obj);
     JSCompartment *target = js::GetContextCompartment(cx);
     bool originIsChrome = AccessCheck::isChrome(origin);
     bool targetIsChrome = AccessCheck::isChrome(target);
     bool originSubsumesTarget = AccessCheck::subsumes(origin, target);
     bool targetSubsumesOrigin = AccessCheck::subsumes(target, origin);
     bool sameOrigin = targetSubsumesOrigin && originSubsumesTarget;
     XrayType xrayType = GetXrayType(obj);
-    bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
 
     // By default we use the wrapped proto of the underlying object as the
     // prototype for our wrapper, but we may select something different below.
     JSObject *proxyProto = wrappedProto;
 
     Wrapper *wrapper;
     CompartmentPrivate *targetdata = EnsureCompartmentPrivate(target);
 
@@ -395,30 +390,16 @@ WrapperFactory::Rewrap(JSContext *cx, JS
                                     ComponentsObjectPolicy>::singleton;
     } else if (AccessCheck::needsSystemOnlyWrapper(obj) &&
                !(targetIsChrome || (targetSubsumesOrigin && nsContentUtils::IsCallerXBL())))
     {
         wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
                                     OnlyIfSubjectIsSystem>::singleton;
     }
 
-    // Normally, a non-xrayable non-waived content object that finds itself in
-    // a privileged scope is wrapped with a CrossCompartmentWrapper, even though
-    // the lack of a waiver _really_ should give it an opaque wrapper. This is
-    // a bit too entrenched to change for content-chrome, but we can at least fix
-    // it for XBL scopes.
-    //
-    // See bug 843829.
-    else if (targetSubsumesOrigin && !originSubsumesTarget &&
-             !waiveXrayFlag && xrayType == NotXray &&
-             IsXBLScope(target))
-    {
-        wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton;
-    }
-
     //
     // Now, handle the regular cases.
     //
     // These are wrappers we can compute using a rule-based approach. In order
     // to do so, we need to compute some parameters.
     //
     else {
 
@@ -431,17 +412,18 @@ WrapperFactory::Rewrap(JSContext *cx, JS
         // and the caller has not requested same-origin Xrays.
         //
         // Xrays are a bidirectional protection, since it affords clarity to the
         // caller and privacy to the callee.
         bool wantXrays = !(sameOrigin && !targetdata->wantXrays);
 
         // If Xrays are warranted, the caller may waive them for non-security
         // wrappers.
-        bool waiveXrays = wantXrays && !securityWrapper && waiveXrayFlag;
+        bool waiveXrays = wantXrays && !securityWrapper &&
+                          (flags & WAIVE_XRAY_WRAPPER_FLAG);
 
         wrapper = SelectWrapper(securityWrapper, wantXrays, xrayType, waiveXrays);
     }
 
 
 
     // If the prototype of a chrome object being wrapped in content is a prototype
     // for a standard class, use the one from the content compartment so
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1298,17 +1298,17 @@ XrayWrapper<Base, Traits>::XrayWrapper(u
 template <typename Base, typename Traits>
 XrayWrapper<Base, Traits>::~XrayWrapper()
 {
 }
 
 namespace XrayUtils {
 
 bool
-NeedsWaive(JSContext *cx, HandleObject wrapper, HandleId id)
+IsTransparent(JSContext *cx, HandleObject wrapper, HandleId id)
 {
     // We dynamically waive Xray vision for XBL bindings accessing fields
     // on bound elements, since there's no way to access such things sanely
     // over Xray.
     nsCOMPtr<nsIContent> content;
     if (EnsureCompartmentPrivate(wrapper)->scope->IsXBLScope() &&
         (content = do_QueryInterfaceNative(cx, wrapper)))
     {
@@ -1451,21 +1451,28 @@ XrayWrapper<Base, Traits>::getPropertyDe
     RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
     if (Traits::isResolving(cx, holder, id)) {
         desc->obj = NULL;
         return true;
     }
 
     typename Traits::ResolvingIdImpl resolving(wrapper, id);
 
-    if (XrayUtils::NeedsWaive(cx, wrapper, id)) {
-        RootedObject waived(cx, WrapperFactory::WaiveXray(cx, wrapper));
-        if (!waived || !JS_WrapObject(cx, waived.address()))
-            return false;
-        return JS_GetPropertyDescriptorById(cx, waived, id, flags, desc);
+    // Redirect access straight to the wrapper if we should be transparent.
+    if (XrayUtils::IsTransparent(cx, wrapper, id)) {
+        RootedObject obj(cx, Traits::getTargetObject(wrapper));
+        {
+            JSAutoCompartment ac(cx, obj);
+            if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
+                return false;
+        }
+
+        if (desc->obj)
+            desc->obj = wrapper;
+        return JS_WrapPropertyDescriptor(cx, desc);
     }
 
     if (!holder)
         return false;
 
     // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
     // get .wrappedJSObject. We can check this by determining if the compartment
     // of the wrapper subsumes that of the wrappee.
@@ -1587,26 +1594,27 @@ XrayWrapper<Base, Traits>::getOwnPropert
         desc->obj = NULL;
         return true;
     }
 
     typename Traits::ResolvingIdImpl resolving(wrapper, id);
 
     // NB: Nothing we do here acts on the wrapped native itself, so we don't
     // enter our policy.
+    // Redirect access straight to the wrapper if we should be transparent.
+    if (XrayUtils::IsTransparent(cx, wrapper, id)) {
+        RootedObject obj(cx, Traits::getTargetObject(wrapper));
+        {
+            JSAutoCompartment ac(cx, obj);
+            if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
+                return false;
+        }
 
-    if (XrayUtils::NeedsWaive(cx, wrapper, id)) {
-        RootedObject waived(cx, WrapperFactory::WaiveXray(cx, wrapper));
-        if (!waived || !JS_WrapObject(cx, waived.address()))
-            return false;
-        if (!JS_GetPropertyDescriptorById(cx, waived, id, flags, desc))
-            return false;
-        if (desc->obj != waived)
-            desc->obj = nullptr;
-        return true;
+        desc->obj = (desc->obj == obj) ? wrapper.get() : nullptr; // XXX
+        return JS_WrapPropertyDescriptor(cx, desc);
     }
 
     if (!Traits::singleton.resolveOwnProperty(cx, *this, wrapper, holder, id, desc, flags))
         return false;
 
     if (desc->obj) {
         desc->obj = wrapper;
         return true;
@@ -1623,21 +1631,24 @@ XrayWrapper<Base, Traits>::getOwnPropert
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, HandleObject wrapper,
                                           HandleId id, PropertyDescriptor *desc)
 {
     assertEnteredPolicy(cx, wrapper, id);
-    if (XrayUtils::NeedsWaive(cx, wrapper, id)) {
-        RootedObject waived(cx, WrapperFactory::WaiveXray(cx, wrapper));
-        if (!waived || !JS_WrapObject(cx, waived.address()))
+    // Redirect access straight to the wrapper if we should be transparent.
+    if (XrayUtils::IsTransparent(cx, wrapper, id)) {
+        RootedObject obj(cx, Traits::getTargetObject(wrapper));
+        JSAutoCompartment ac(cx, obj);
+        if (!JS_WrapPropertyDescriptor(cx, desc))
             return false;
-        return JS_DefinePropertyById(cx, waived, id, desc->value, desc->getter, desc->setter,
+
+        return JS_DefinePropertyById(cx, obj, id, desc->value, desc->getter, desc->setter,
                                      desc->attrs);
     }
 
     // NB: We still need JSRESOLVE_ASSIGNING here for the time being, because it
     // tells things like nodelists whether they should create the property or not.
     PropertyDescriptor existing_desc;
     if (!getOwnPropertyDescriptor(cx, wrapper, id, &existing_desc, JSRESOLVE_ASSIGNING))
         return false;
@@ -1682,16 +1693,29 @@ XrayWrapper<Base, Traits>::getOwnPropert
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::delete_(JSContext *cx, HandleObject wrapper,
                                    HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, wrapper, id);
+    // Redirect access straight to the wrapper if we should be transparent.
+    if (XrayUtils::IsTransparent(cx, wrapper, id)) {
+        RootedObject obj(cx, Traits::getTargetObject(wrapper));
+
+        JSAutoCompartment ac(cx, obj);
+
+        JSBool b;
+        RootedValue v(cx);
+        if (!JS_DeletePropertyById2(cx, obj, id, v.address()) || !JS_ValueToBoolean(cx, v, &b))
+            return false;
+        *bp = !!b;
+        return true;
+    }
 
     // Check the expando object.
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject expando(cx, Traits::singleton.getExpandoObject(cx, target, wrapper));
     JSBool b = true;
     if (expando) {
         JSAutoCompartment ac(cx, expando);
         RootedValue v(cx);
@@ -1706,16 +1730,23 @@ XrayWrapper<Base, Traits>::delete_(JSCon
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags,
                                      AutoIdVector &props)
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID);
+    // Redirect access straight to the wrapper if we should be transparent.
+    if (XrayUtils::IsTransparent(cx, wrapper, JSID_VOIDHANDLE)) {
+        RootedObject obj(cx, Traits::getTargetObject(wrapper));
+        JSAutoCompartment ac(cx, obj);
+        return js::GetPropertyNames(cx, obj, flags, &props);
+    }
+
     if (!AccessCheck::wrapperSubsumes(wrapper)) {
         JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
         return false;
     }
 
     // Enumerate expando properties first. Note that the expando object lives
     // in the target compartment.
     RootedObject target(cx, Traits::singleton.getTargetObject(wrapper));