Bug 1528383 - Allow getting 'wrappedJSObject' without the attribute being defined, r=bholley
authorNika Layzell <nika@thelayzells.com>
Tue, 26 Feb 2019 21:19:11 +0000
changeset 519430 8e58294baf24a304a10a1ac46607abc7711ad0a3
parent 519429 c2091f595c72666fdc160828a3577aac7974f1ba
child 519431 b437ff8ed47c2bad4b0351ac26453459a89cbb44
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1528383
milestone67.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 1528383 - Allow getting 'wrappedJSObject' without the attribute being defined, r=bholley Differential Revision: https://phabricator.services.mozilla.com/D20016
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -168,60 +168,54 @@ static bool XPC_WN_Shared_toPrimitive(JS
  *    // bar is the underlying JSObject. Do stuff with it here.
  * }
  *
  * Recall that 'foo' above is an XPConnect wrapper, not the underlying JS
  * object. The property get "foo.wrappedJSObject" will only succeed if three
  * conditions are met:
  *
  * 1) 'foo' really is an XPConnect wrapper around a JSObject.
- * 2) The underlying JSObject actually implements a "wrappedJSObject"
- *    property that returns a JSObject. This is called by XPConnect. This
- *    restriction allows wrapped objects to only allow access to the underlying
- *    JSObject if they choose to do so. Usually this just means that 'foo'
- *    would have a property that looks like:
- *       this.wrappedJSObject = this.
  * 3) The caller must be system JS and not content. Double-wrapped XPCWJS should
  *    not be exposed to content except with enablePrivilege or a remote-XUL
  *    domain.
  *
  * Notes:
  *
  * a) If 'foo' above were the underlying JSObject and not a wrapper at all,
  *    then this all just works and XPConnect is not part of the picture at all.
  * b) One might ask why 'foo' should not just implement an interface through
- *    which callers might get at the underlying object. There are three reasons:
+ *    which callers might get at the underlying object. There are two reasons:
  *   i)   XPConnect would still have to do magic since JSObject is not a
  *        scriptable type.
- *   ii)  JS Components might use aggregation (like C++ objects) and have
- *        different JSObjects for different interfaces 'within' an aggregate
- *        object. But, using an additional interface only allows returning one
- *        underlying JSObject. However, this allows for the possibility that
- *        each of the aggregte JSObjects could return something different.
- *        Note that one might do: this.wrappedJSObject = someOtherObject;
- *   iii) Avoiding the explicit interface makes it easier for both the caller
+ *   ii)  Avoiding the explicit interface makes it easier for both the caller
  *        and the component.
  */
 
 static JSObject* GetDoubleWrappedJSObject(XPCCallContext& ccx,
                                           XPCWrappedNative* wrapper) {
   RootedObject obj(ccx);
   nsCOMPtr<nsIXPConnectWrappedJS> underware =
       do_QueryInterface(wrapper->GetIdentityObject());
   if (underware) {
     RootedObject mainObj(ccx, underware->GetJSObject());
     if (mainObj) {
-      RootedId id(ccx, ccx.GetContext()->GetStringID(
-                           XPCJSContext::IDX_WRAPPED_JSOBJECT));
-
       JSAutoRealm ar(ccx, underware->GetJSObjectGlobal());
 
+      // We don't have to root this ID, as it's already rooted by our context.
+      HandleId id =
+          ccx.GetContext()->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT);
+
+      // If the `wrappedJSObject` property is defined, use the result of getting
+      // that property, otherwise fall back to the `mainObj` object which is
+      // directly being wrapped.
       RootedValue val(ccx);
       if (JS_GetPropertyById(ccx, mainObj, id, &val) && !val.isPrimitive()) {
         obj = val.toObjectOrNull();
+      } else {
+        obj = mainObj;
       }
     }
   }
   return obj;
 }
 
 // This is the getter native function we use to handle 'wrappedJSObject' for
 // double wrapped JSObjects.