--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -73,16 +73,17 @@ public:
#define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)"
#define LOAD_ERROR_NOSCHEME "Failed to get URI scheme. This is bad."
#define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI."
#define LOAD_ERROR_NOSTREAM "Error opening input stream (invalid filename?)"
#define LOAD_ERROR_NOCONTENT "ContentLength not available (not a local URL?)"
#define LOAD_ERROR_BADCHARSET "Error converting to specified charset"
#define LOAD_ERROR_NOSPEC "Failed to get URI spec. This is bad."
#define LOAD_ERROR_CONTENTTOOBIG "ContentLength is too large"
+#define LOAD_ERROR_NO_COMPILATION_SCOPE "Failed to initialize compilation scope"
mozJSSubScriptLoader::mozJSSubScriptLoader()
{
}
mozJSSubScriptLoader::~mozJSSubScriptLoader()
{
}
@@ -245,17 +246,19 @@ EvalScript(JSContext* cx,
// This has the side-effect of keeping the global that the script
// was compiled for alive, too.
//
// For most startups, the global in question will be the
// CompilationScope, since we pre-compile any scripts that were
// needed during the last startup in that scope. But for startups
// when a non-cached script is used (e.g., after add-on
// installation), this may be a Sandbox global, which may be
- // nuked but held alive by the JSScript.
+ // nuked but held alive by the JSScript. We can avoid this problem
+ // by using a different scope when compiling the script. See
+ // useCompilationScope in ReadScript().
//
// In general, this isn't a problem, since add-on Sandboxes which
// use the script preloader are not destroyed until add-on shutdown,
// and when add-ons are uninstalled or upgraded, the preloader cache
// is immediately flushed after shutdown. But it's possible to
// disable and reenable an add-on without uninstalling it, leading
// to cached scripts being held alive, and tied to nuked Sandbox
// globals. Given the unusual circumstances required to trigger
@@ -499,16 +502,17 @@ mozJSSubScriptLoader::ReadScriptAsync(ns
bool
mozJSSubScriptLoader::ReadScript(nsIURI* uri,
JSContext* cx,
HandleObject targetObj,
const nsAString& charset,
const char* uriStr,
nsIIOService* serv,
bool wantReturnValue,
+ bool useCompilationScope,
MutableHandleScript script)
{
script.set(nullptr);
// We create a channel and call SetContentType, to avoid expensive MIME type
// lookups (bug 632490).
nsCOMPtr<nsIChannel> chan;
nsCOMPtr<nsIInputStream> instream;
@@ -546,16 +550,34 @@ mozJSSubScriptLoader::ReadScript(nsIURI*
ReportError(cx, LOAD_ERROR_CONTENTTOOBIG, uri);
return false;
}
nsCString buf;
rv = NS_ReadInputStreamToString(instream, buf, len);
NS_ENSURE_SUCCESS(rv, false);
+ AutoJSAPI jsapi;
+
+ // Note that when using the ScriptPreloader cache with loadSubScript, there
+ // will be a side-effect of keeping the global that the script was compiled
+ // for alive. See note above in EvalScript().
+ //
+ // This will compile the script in XPConnect compilation scope. When the
+ // script is evaluated, it will be cloned into the target scope to be
+ // executed, avoiding leaks on the first session when we don't have a
+ // startup cache.
+ if (useCompilationScope) {
+ if (!jsapi.Init(xpc::CompilationScope())) {
+ ReportError(cx, LOAD_ERROR_NO_COMPILATION_SCOPE, uri);
+ return false;
+ }
+ cx = jsapi.cx();
+ }
+
return PrepareScript(uri, cx, targetObj, uriStr, charset,
buf.get(), len, wantReturnValue,
script);
}
NS_IMETHODIMP
mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
HandleValue target,
@@ -715,17 +737,18 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
}
if (script) {
// |script| came from the cache, so don't bother writing it
// |back there.
cache = nullptr;
} else if (!ReadScript(uri, cx, targetObj, options.charset,
static_cast<const char*>(uriStr.get()), serv,
- options.wantReturnValue, &script)) {
+ options.wantReturnValue,
+ isCodebaseFile && !options.wantReturnValue, &script)) {
return NS_OK;
}
Unused << EvalScript(cx, targetObj, loadScope, retval, uri, !!cache,
!ignoreCache && !options.wantReturnValue,
&script);
return NS_OK;
}
--- a/js/xpconnect/loader/mozJSSubScriptLoader.h
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.h
@@ -31,17 +31,17 @@ public:
NS_DECL_MOZIJSSUBSCRIPTLOADER
private:
virtual ~mozJSSubScriptLoader();
bool ReadScript(nsIURI* uri, JSContext* cx, JS::HandleObject targetObj,
const nsAString& charset, const char* uriStr,
nsIIOService* serv,
- bool wantReturnValue,
+ bool wantReturnValue, bool useCompilationScope,
JS::MutableHandleScript script);
nsresult ReadScriptAsync(nsIURI* uri,
JS::HandleObject targetObj,
JS::HandleObject loadScope,
const nsAString& charset,
nsIIOService* serv,
bool wantReturnValue,