Bug 1070131 - Stop XDR-serializing origin principals. r=luke,r=bz
authorBobby Holley <bobbyholley@gmail.com>
Mon, 29 Sep 2014 10:44:30 +0200
changeset 207624 b9bfd9b37fe82071ac5da7360608fd301f98e57e
parent 207623 1e4da0087b72e306f9aa78d69b1465c17fe775d2
child 207625 ee03a0b3b0375e344abb72d775350a97529408a6
push id49738
push userbobbyholley@gmail.com
push dateMon, 29 Sep 2014 08:44:52 +0000
treeherdermozilla-inbound@ee03a0b3b037 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke, bz
bugs1070131
milestone35.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 1070131 - Stop XDR-serializing origin principals. r=luke,r=bz
js/src/jsapi-tests/testXDR.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsscript.cpp
js/src/shell/js.cpp
js/src/vm/Xdr.cpp
js/src/vm/Xdr.h
js/xpconnect/loader/mozJSLoaderUtils.cpp
js/xpconnect/src/nsXPConnect.cpp
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -8,153 +8,38 @@
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "jsapi-tests/tests.h"
 
 #include "jsscriptinlines.h"
 
 static JSScript *
-CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj,
-                                        JSPrincipals *originPrincipals,
-                                        const char *bytes, size_t nbytes,
-                                        const char *filename, unsigned lineno,
-                                        JSVersion version)
-{
-    size_t nchars;
-    if (!JS_DecodeBytes(cx, bytes, nbytes, nullptr, &nchars))
-        return nullptr;
-    char16_t *chars = static_cast<char16_t *>(JS_malloc(cx, nchars * sizeof(char16_t)));
-    if (!chars)
-        return nullptr;
-    JS_ALWAYS_TRUE(JS_DecodeBytes(cx, bytes, nbytes, chars, &nchars));
-    JS::CompileOptions options(cx);
-    options.setOriginPrincipals(originPrincipals)
-           .setFileAndLine(filename, lineno)
-           .setVersion(version);
-    JS::RootedScript script(cx);
-    JS::Compile(cx, obj, options, chars, nchars, &script);
-    JS_free(cx, chars);
-    return script;
-}
-
-static JSScript *
 FreezeThaw(JSContext *cx, JS::HandleScript script)
 {
     // freeze
     uint32_t nbytes;
     void *memory = JS_EncodeScript(cx, script, &nbytes);
     if (!memory)
         return nullptr;
 
     // thaw
-    JSScript *script2 = JS_DecodeScript(cx, memory, nbytes,
-                                        script->originPrincipals());
+    JSScript *script2 = JS_DecodeScript(cx, memory, nbytes);
     js_free(memory);
     return script2;
 }
 
-static JSScript *
-GetScript(JSContext *cx, JS::HandleObject funobj)
-{
-    JS::RootedFunction fun(cx, JS_GetObjectFunction(funobj));
-    return JS_GetFunctionScript(cx, fun);
-}
-
-static JSObject *
-FreezeThaw(JSContext *cx, JS::HandleObject funobj)
-{
-    // freeze
-    uint32_t nbytes;
-    void *memory = JS_EncodeInterpretedFunction(cx, funobj, &nbytes);
-    if (!memory)
-        return nullptr;
-
-    // thaw
-    JSScript *script = GetScript(cx, funobj);
-    JSObject *funobj2 = JS_DecodeInterpretedFunction(cx, memory, nbytes,
-                                                     script->originPrincipals());
-    js_free(memory);
-    return funobj2;
-}
-
-static TestJSPrincipals testPrincipal0(1);
-static TestJSPrincipals testPrincipal1(1);
-
-BEGIN_TEST(testXDR_principals)
-{
-    JSScript *script;
-    JSCompartment *compartment = js::GetContextCompartment(cx);
-    for (int i = TEST_FIRST; i != TEST_END; ++i) {
-        // Appease the new JSAPI assertions. The stuff being tested here is
-        // going away anyway.
-        JS_SetCompartmentPrincipals(compartment, &testPrincipal0);
-        script = createScriptViaXDR(nullptr, i);
-        CHECK(script);
-        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
-        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal0);
-
-        script = createScriptViaXDR(&testPrincipal0, i);
-        CHECK(script);
-        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
-        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal0);
-
-        script = createScriptViaXDR(&testPrincipal1, i);
-        CHECK(script);
-        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
-        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal1);
-    }
-
-    return true;
-}
-
 enum TestCase {
     TEST_FIRST,
     TEST_SCRIPT = TEST_FIRST,
     TEST_FUNCTION,
     TEST_SERIALIZED_FUNCTION,
     TEST_END
 };
 
-JSScript *createScriptViaXDR(JSPrincipals *orig, int testCase)
-{
-    const char src[] =
-        "function f() { return 1; }\n"
-        "f;\n";
-
-    JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
-    JS::RootedScript script(cx, CompileScriptForPrincipalsVersionOrigin(cx, global, orig,
-                                                                        src, strlen(src), "test", 1,
-                                                                        JSVERSION_DEFAULT));
-    if (!script)
-        return nullptr;
-
-    if (testCase == TEST_SCRIPT || testCase == TEST_SERIALIZED_FUNCTION) {
-        script = FreezeThaw(cx, script);
-        if (!script)
-            return nullptr;
-        if (testCase == TEST_SCRIPT)
-            return script;
-    }
-
-    JS::RootedValue v(cx);
-    bool ok = JS_ExecuteScript(cx, global, script, &v);
-    if (!ok || !v.isObject())
-        return nullptr;
-    JS::RootedObject funobj(cx, &v.toObject());
-    if (testCase == TEST_FUNCTION) {
-        funobj = FreezeThaw(cx, funobj);
-        if (!funobj)
-            return nullptr;
-    }
-    return GetScript(cx, funobj);
-}
-
-END_TEST(testXDR_principals)
-
 BEGIN_TEST(testXDR_bug506491)
 {
     const char *s =
         "function makeClosure(s, name, value) {\n"
         "    eval(s);\n"
         "    Math.sin(value);\n"
         "    return let (n = name, v = value) function () { return String(v); };\n"
         "}\n"
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6499,31 +6499,29 @@ JS_EncodeInterpretedFunction(JSContext *
     XDREncoder encoder(cx);
     RootedObject funobj(cx, funobjArg);
     if (!encoder.codeFunction(&funobj))
         return nullptr;
     return encoder.forgetData(lengthp);
 }
 
 JS_PUBLIC_API(JSScript *)
-JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
-                JSPrincipals *originPrincipals)
-{
-    XDRDecoder decoder(cx, data, length, originPrincipals);
+JS_DecodeScript(JSContext *cx, const void *data, uint32_t length)
+{
+    XDRDecoder decoder(cx, data, length);
     RootedScript script(cx);
     if (!decoder.codeScript(&script))
         return nullptr;
     return script;
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
-                             JSPrincipals *originPrincipals)
-{
-    XDRDecoder decoder(cx, data, length, originPrincipals);
+JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length)
+{
+    XDRDecoder decoder(cx, data, length);
     RootedObject funobj(cx);
     if (!decoder.codeFunction(&funobj))
         return nullptr;
     return funobj;
 }
 
 JS_PUBLIC_API(bool)
 JS_PreventExtensions(JSContext *cx, JS::HandleObject obj)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5059,21 +5059,20 @@ class AutoHideScriptedCaller
 
 extern JS_PUBLIC_API(void *)
 JS_EncodeScript(JSContext *cx, JS::HandleScript script, uint32_t *lengthp);
 
 extern JS_PUBLIC_API(void *)
 JS_EncodeInterpretedFunction(JSContext *cx, JS::HandleObject funobj, uint32_t *lengthp);
 
 extern JS_PUBLIC_API(JSScript *)
-JS_DecodeScript(JSContext *cx, const void *data, uint32_t length, JSPrincipals *originPrincipals);
+JS_DecodeScript(JSContext *cx, const void *data, uint32_t length);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
-                             JSPrincipals *originPrincipals);
+JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length);
 
 namespace JS {
 
 /*
  * This callback represents a request by the JS engine to open for reading the
  * existing cache entry for the given global and char range that may contain a
  * module. If a cache entry exists, the callback shall return 'true' and return
  * the size, base address and an opaque file handle as outparams. If the
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -734,17 +734,16 @@ js::XDRScript(XDRState<mode> *xdr, Handl
 
             /*
              * We use this CompileOptions only to initialize the
              * ScriptSourceObject. Most CompileOptions fields aren't used by
              * ScriptSourceObject, and those that are (element; elementAttributeName)
              * aren't preserved by XDR. So this can be simple.
              */
             CompileOptions options(cx);
-            options.setOriginPrincipals(xdr->originPrincipals());
             ss->initFromOptions(cx, options);
             sourceObject = ScriptSourceObject::create(cx, ss);
             if (!sourceObject ||
                 !ScriptSourceObject::initFromOptions(cx, sourceObject, options))
                 return false;
         } else {
             JS_ASSERT(enclosingScript);
             // When decoding, all the scripts and the script source object
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1262,17 +1262,17 @@ Evaluate(JSContext *cx, unsigned argc, j
                     JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                          JSSMSG_CACHE_SINGLETON_FAILED);
                     return false;
                 }
                 JS::CompartmentOptionsRef(cx).setCloneSingletons(true);
             }
 
             if (loadBytecode) {
-                script = JS_DecodeScript(cx, loadBuffer, loadLength, options.originPrincipals(cx));
+                script = JS_DecodeScript(cx, loadBuffer, loadLength);
             } else {
                 mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
                 (void) JS::Compile(cx, global, options, chars.start().get(), chars.length(), &script);
             }
 
             if (!script)
                 return false;
         }
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -133,18 +133,16 @@ XDRState<mode>::codeScript(MutableHandle
 
 template<XDRMode mode>
 bool
 XDRState<mode>::codeConstValue(MutableHandleValue vp)
 {
     return XDRScriptConst(this, vp);
 }
 
-XDRDecoder::XDRDecoder(JSContext *cx, const void *data, uint32_t length,
-                       JSPrincipals *originPrincipals)
+XDRDecoder::XDRDecoder(JSContext *cx, const void *data, uint32_t length)
   : XDRState<XDR_DECODE>(cx)
 {
     buf.setData(data, length);
-    this->originPrincipals_ = originPrincipals;
 }
 
 template class js::XDRState<XDR_ENCODE>;
 template class js::XDRState<XDR_DECODE>;
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -23,17 +23,17 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 184);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 185);
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;
@@ -95,31 +95,25 @@ class XDRBuffer {
  * XDR serialization state.  All data is encoded in little endian.
  */
 template <XDRMode mode>
 class XDRState {
   public:
     XDRBuffer buf;
 
   protected:
-    JSPrincipals *originPrincipals_;
-
     explicit XDRState(JSContext *cx)
-      : buf(cx), originPrincipals_(nullptr) {
+      : buf(cx) {
     }
 
   public:
     JSContext *cx() const {
         return buf.cx();
     }
 
-    JSPrincipals *originPrincipals() const {
-        return originPrincipals_;
-    }
-
     bool codeUint8(uint8_t *n) {
         if (mode == XDR_ENCODE) {
             uint8_t *ptr = buf.write(sizeof *n);
             if (!ptr)
                 return false;
             *ptr = *n;
         } else {
             *n = *buf.read(sizeof *n);
@@ -255,16 +249,15 @@ class XDREncoder : public XDRState<XDR_E
         void *data = buf.getData(lengthp);
         buf.setData(nullptr, 0);
         return data;
     }
 };
 
 class XDRDecoder : public XDRState<XDR_DECODE> {
   public:
-    XDRDecoder(JSContext *cx, const void *data, uint32_t length,
-               JSPrincipals *originPrincipals);
+    XDRDecoder(JSContext *cx, const void *data, uint32_t length);
 
 };
 
 } /* namespace js */
 
 #endif /* vm_Xdr_h */
--- a/js/xpconnect/loader/mozJSLoaderUtils.cpp
+++ b/js/xpconnect/loader/mozJSLoaderUtils.cpp
@@ -26,17 +26,17 @@ ReadCachedScript(StartupCache* cache, ns
 {
     nsAutoArrayPtr<char> buf;
     uint32_t len;
     nsresult rv = cache->GetBuffer(PromiseFlatCString(uri).get(),
                                    getter_Transfers(buf), &len);
     if (NS_FAILED(rv))
         return rv; // don't warn since NOT_AVAILABLE is an ok error
 
-    scriptp.set(JS_DecodeScript(cx, buf, len, nullptr));
+    scriptp.set(JS_DecodeScript(cx, buf, len));
     if (!scriptp)
         return NS_ERROR_OUT_OF_MEMORY;
     return NS_OK;
 }
 
 nsresult
 ReadCachedFunction(StartupCache* cache, nsACString &uri, JSContext *cx,
                    nsIPrincipal *systemPrincipal, JSFunction **functionp)
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1293,55 +1293,34 @@ SetLocationForGlobal(JSObject *global, n
 
 NS_IMETHODIMP
 nsXPConnect::NotifyDidPaint()
 {
     JS::NotifyDidPaint(GetRuntime()->Runtime());
     return NS_OK;
 }
 
-// Note - We used to have HAS_PRINCIPALS_FLAG = 1 here, so reusing that flag
-// will require bumping the XDR version number.
-static const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG        = 2;
-
 static nsresult
 WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
                       JSScript *scriptArg, HandleObject functionObj)
 {
     // Exactly one of script or functionObj must be given
     MOZ_ASSERT(!scriptArg != !functionObj);
 
     RootedScript script(cx, scriptArg);
     if (!script) {
         RootedFunction fun(cx, JS_GetObjectFunction(functionObj));
         script.set(JS_GetFunctionScript(cx, fun));
     }
 
-    nsIPrincipal *principal =
-        nsJSPrincipals::get(JS_GetScriptPrincipals(script));
-    nsIPrincipal *originPrincipal =
-        nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script));
-
-    uint8_t flags = 0;
-
-    // Optimize for the common case when originPrincipals == principals. As
-    // originPrincipals is set to principals when the former is null we can
-    // simply skip the originPrincipals when they are the same as principals.
-    if (originPrincipal && originPrincipal != principal)
-        flags |= HAS_ORIGIN_PRINCIPALS_FLAG;
-
+    uint8_t flags = 0; // We don't have flags anymore.
     nsresult rv = stream->Write8(flags);
     if (NS_FAILED(rv))
         return rv;
 
-    if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
-        rv = stream->WriteObject(originPrincipal, true);
-        if (NS_FAILED(rv))
-            return rv;
-    }
 
     uint32_t size;
     void* data;
     {
         if (functionObj)
             data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
         else
             data = JS_EncodeScript(cx, script, &size);
@@ -1365,47 +1344,41 @@ ReadScriptOrFunction(nsIObjectInputStrea
     // Exactly one of script or functionObj must be given
     MOZ_ASSERT(!scriptp != !functionObjp);
 
     uint8_t flags;
     nsresult rv = stream->Read8(&flags);
     if (NS_FAILED(rv))
         return rv;
 
-    nsJSPrincipals* originPrincipal = nullptr;
-    nsCOMPtr<nsIPrincipal> readOriginPrincipal;
-    if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
-        nsCOMPtr<nsISupports> supports;
-        rv = stream->ReadObject(true, getter_AddRefs(supports));
-        if (NS_FAILED(rv))
-            return rv;
-        readOriginPrincipal = do_QueryInterface(supports);
-        originPrincipal = nsJSPrincipals::get(readOriginPrincipal);
-    }
+    // We don't serialize mutedError-ness of scripts, which is fine as long as
+    // we only serialize system and XUL-y things. We can detect this by checking
+    // where the caller wants us to deserialize.
+    MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome() ||
+                       CurrentGlobalOrNull(cx) == xpc::CompilationScope());
 
     uint32_t size;
     rv = stream->Read32(&size);
     if (NS_FAILED(rv))
         return rv;
 
     char* data;
     rv = stream->ReadBytes(size, &data);
     if (NS_FAILED(rv))
         return rv;
 
     {
         if (scriptp) {
-            JSScript *script = JS_DecodeScript(cx, data, size, originPrincipal);
+            JSScript *script = JS_DecodeScript(cx, data, size);
             if (!script)
                 rv = NS_ERROR_OUT_OF_MEMORY;
             else
                 *scriptp = script;
         } else {
-            JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size,
-                                                            originPrincipal);
+            JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size);
             if (!funobj)
                 rv = NS_ERROR_OUT_OF_MEMORY;
             else
                 *functionObjp = funobj;
         }
     }
 
     nsMemory::Free(data);