Bug 977340 - Do some gymnastics to avoid tripping cx assertions when cloning exceptions from evalInWindow calls. r=gabor
authorBobby Holley <bobbyholley@gmail.com>
Tue, 04 Mar 2014 10:05:08 -0800
changeset 171758 3c8c8d1b869b9f481b8d69563a999806e556b522
parent 171757 681a088dd2b8ee51196d32b108f463993dc2eeae
child 171759 219a096d2d1e7b22ce2ed5fc07d3d219bd7d6c88
push id40557
push userbobbyholley@gmail.com
push dateTue, 04 Mar 2014 18:05:18 +0000
treeherdermozilla-inbound@de377011ed9d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor
bugs977340
milestone30.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 977340 - Do some gymnastics to avoid tripping cx assertions when cloning exceptions from evalInWindow calls. r=gabor
js/src/jscntxtinlines.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/xpconnect/src/Sandbox.cpp
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -363,17 +363,19 @@ ExclusiveContext::typeLifoAlloc()
 }  /* namespace js */
 
 inline void
 JSContext::setPendingException(js::Value v)
 {
     JS_ASSERT(!IsPoisonedValue(v));
     this->throwing = true;
     this->unwrappedException_ = v;
-    js::assertSameCompartment(this, v);
+    // We don't use assertSameCompartment here to allow
+    // js::SetPendingExceptionCrossContext to work.
+    JS_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
 }
 
 inline void
 JSContext::setDefaultCompartmentObject(JSObject *obj)
 {
     JS_ASSERT(!options().noDefaultCompartmentObject());
     defaultCompartmentObject_ = obj;
 }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -389,16 +389,22 @@ js::GetObjectParentMaybeScope(JSObject *
 
 JS_FRIEND_API(JSObject *)
 js::GetGlobalForObjectCrossCompartment(JSObject *obj)
 {
     return &obj->global();
 }
 
 JS_FRIEND_API(void)
+js::SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v)
+{
+    cx->setPendingException(v);
+}
+
+JS_FRIEND_API(void)
 js::AssertSameCompartment(JSContext *cx, JSObject *obj)
 {
     assertSameCompartment(cx, obj);
 }
 
 #ifdef DEBUG
 JS_FRIEND_API(void)
 js::AssertSameCompartment(JSObject *objA, JSObject *objB)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -656,16 +656,21 @@ GetObjectCompartment(JSObject *obj)
 }
 
 JS_FRIEND_API(JSObject *)
 GetObjectParentMaybeScope(JSObject *obj);
 
 JS_FRIEND_API(JSObject *)
 GetGlobalForObjectCrossCompartment(JSObject *obj);
 
+// Sidestep the activeContext checking implicitly performed in
+// JS_SetPendingException.
+JS_FRIEND_API(void)
+SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v);
+
 JS_FRIEND_API(void)
 AssertSameCompartment(JSContext *cx, JSObject *obj);
 
 #ifdef JS_DEBUG
 JS_FRIEND_API(void)
 AssertSameCompartment(JSObject *objA, JSObject *objB);
 #else
 inline void AssertSameCompartment(JSObject *objA, JSObject *objB) {}
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -505,16 +505,17 @@ EvalInWindow(JSContext *cx, const nsAStr
     nsCString filename;
     unsigned lineNo;
     if (!GetFilenameAndLineNumber(cx, filename, lineNo)) {
         // Default values for non-scripted callers.
         filename.Assign("Unknown");
         lineNo = 0;
     }
 
+    RootedObject cxGlobal(cx, JS::CurrentGlobalOrNull(cx));
     {
         // CompileOptions must be created from the context
         // we will execute this script in.
         JSContext *wndCx = context->GetNativeContext();
         AutoCxPusher pusher(wndCx);
         JS::CompileOptions compileOptions(wndCx);
         compileOptions.setFileAndLine(filename.get(), lineNo);
 
@@ -543,18 +544,19 @@ EvalInWindow(JSContext *cx, const nsAStr
 
             // If there was an exception thrown we should set it
             // on the calling context.
             RootedValue exn(wndCx, rval);
             // First we should reset the return value.
             rval.set(UndefinedValue());
 
             // Then clone the exception.
-            if (CloneNonReflectors(cx, &exn))
-                JS_SetPendingException(cx, exn);
+            JSAutoCompartment ac(wndCx, cxGlobal);
+            if (CloneNonReflectors(wndCx, &exn))
+                js::SetPendingExceptionCrossContext(cx, exn);
 
             return false;
         }
     }
 
     // Let's clone the return value back to the callers compartment.
     if (!CloneNonReflectors(cx, rval)) {
         rval.set(UndefinedValue());