Bug 1237177 - Make the this-rebinding callable proxy sandboxes use return the prototype of its target, not its own null prototype. r=efaust, a=lizzard
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 11 Jan 2016 12:58:41 -0500
changeset 310845 9247229e7aa2fcddd2b92bc286f1691fc511baa7
parent 310844 7990e9d7ec79a722c676d2715fefd02c132e12ea
child 310846 c1213d2b203ee6b117e57b3b56462747c3de2026
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust, lizzard
bugs1237177
milestone45.0a2
Bug 1237177 - Make the this-rebinding callable proxy sandboxes use return the prototype of its target, not its own null prototype. r=efaust, a=lizzard
dom/tests/mochitest/chrome/test_sandbox_bindings.xul
js/xpconnect/src/Sandbox.cpp
--- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
+++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
@@ -26,16 +26,19 @@ https://bugzilla.mozilla.org/show_bug.cg
   /** Test for Bug 741267 **/
     const Cu = Components.utils;
     function isXrayWrapper(x) {
       return Components.utils.isXrayWrapper(x);
     }
 
     function doTest() {
       var win = $("t").contentWindow;
+      ok(isXrayWrapper(win),
+         "We want to be testing things with an Xray as sandboxPrototype here");
+
       var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
 
       is(sandbox._content, undefined, "_content does nothing over Xray");
 
       try {
         var css = Components.utils.evalInSandbox("CSSStyleDeclaration", sandbox);
         is(String(css.prototype), "[object CSSStyleDeclarationPrototype]",
            "'CSSStyleDeclaration.prototype' in a sandbox should return the CSSStyleDeclaration interface prototype object");
@@ -280,16 +283,36 @@ https://bugzilla.mozilla.org/show_bug.cg
         var doc = Components.utils.evalInSandbox('document', sandbox);
         doc.expando = 5;
         doc.expando = 7;
         is(doc.expando, 7, "Should be able to set expandos on Xrays for DOM bindings with named properties");
       } catch (e) {
         ok(false, "Setting expandos on Xrays shouldn't throw " + e);
       }
 
+      // Test that binding a bareword window method produces something
+      // which has a .call
+      try {
+        var binary = Components.utils.evalInSandbox(
+          'btoa.bind(window).call(null, "foo")', sandbox);
+        is(binary, "Zm9v", "Should get the right result from .call on bound btoa");
+      } catch (e) {
+        ok(false, ".call on bound btoa shouldn't throw " + e);
+      }
+
+      // Test that binding a bareword window method produces something
+      // which has a .apply
+      try {
+        var binary = Components.utils.evalInSandbox(
+          'btoa.bind(window).apply(null, ["foo"])', sandbox);
+        is(binary, "Zm9v", "Should get the right result from .apply on bound btoa");
+      } catch (e) {
+        ok(false, ".apply on bound btoa shouldn't throw " + e);
+      }
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   ]]>
   </script>
 </window>
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -706,18 +706,22 @@ WrapCallable(JSContext* cx, HandleObject
     // Our proxy is wrapping the callable.  So we need to use the
     // callable as the private.  We put the given sandboxProtoProxy in
     // an extra slot, and our call() hook depends on that.
     MOZ_ASSERT(js::IsProxy(sandboxProtoProxy) &&
                js::GetProxyHandler(sandboxProtoProxy) ==
                  &xpc::sandboxProxyHandler);
 
     RootedValue priv(cx, ObjectValue(*callable));
+    // We want to claim to have the same proto as our wrapped callable, so set
+    // ourselves up with a lazy proto.
+    js::ProxyOptions options;
+    options.setLazyProto(true);
     JSObject* obj = js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
-                                       priv, nullptr);
+                                       priv, nullptr, options);
     if (obj) {
         js::SetProxyExtra(obj, SandboxCallableProxyHandler::SandboxProxySlot,
                           ObjectValue(*sandboxProtoProxy));
     }
 
     return obj;
 }