Bug 779724 - Use finer-grain source controls in the browser. r=jorendorff, sr=jst

This commit is contained in:
Benjamin Peterson 2012-08-07 10:39:47 -07:00
parent 6d5b521a81
commit 82fd98ee23
6 changed files with 68 additions and 61 deletions

View File

@ -2497,14 +2497,12 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
// Ok, compile it to create a prototype script object!
nsScriptObjectHolder<JSScript> newScriptObject(context);
uint32_t opts = JS_GetOptions(context->GetNativeContext());
if (!mOutOfLine) {
// If the script was inline, tell the JS parser to save source for
// Function.prototype.toSource(). If it's outline, we retrieve the
// source from the files on demand.
opts &= ~JSOPTION_ONLY_CNG_SOURCE;
JS_SetOptions(context->GetNativeContext(), opts);
}
// If the script was inline, tell the JS parser to save source for
// Function.prototype.toSource(). If it's out of line, we retrieve the
// source from the files on demand.
bool saveSource = !mOutOfLine;
rv = context->CompileScript(aText,
aTextLength,
// Use the enclosing document's principal
@ -2517,8 +2515,8 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
urlspec.get(),
aLineNo,
mLangVersion,
newScriptObject);
JS_SetOptions(context->GetNativeContext(), opts);
newScriptObject,
saveSource);
if (NS_FAILED(rv))
return rv;

View File

@ -45,8 +45,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
NS_ISCRIPTCONTEXTPRINCIPAL_IID)
#define NS_ISCRIPTCONTEXT_IID \
{ 0x9a4df96d, 0xa231, 0x4108, \
{ 0xb5, 0xbc, 0xaf, 0x67, 0x7a, 0x36, 0xa7, 0x44 } }
{ 0x8bdcea47, 0x6704, 0x4dd9, \
{ 0xa1, 0x48, 0x05, 0x34, 0xcf, 0xe2, 0xdd, 0x57 } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@ -114,6 +114,7 @@ public:
* @param aVersion the script language version to use when executing
* @param aScriptObject an executable object that's the result of compiling
* the script.
* @param aSaveSource force the source code to be saved by the JS engine in memory
*
* @return NS_OK if the script source was valid and got compiled.
*
@ -124,7 +125,8 @@ public:
const char* aURL,
PRUint32 aLineNo,
PRUint32 aVersion,
nsScriptObjectHolder<JSScript>& aScriptObject) = 0;
nsScriptObjectHolder<JSScript>& aScriptObject,
bool aSaveSource = false) = 0;
/**
* Execute a precompiled script object.

View File

@ -1074,21 +1074,6 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime)
mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS | JSOPTION_ALLOW_XML;
// The JS engine needs to keep the source code around in order to implement
// Function.prototype.toSource(). JSOPTION_ONLY_CNG_SOURCE causes the JS
// engine to retain the source code for scripts compiled in compileAndGo mode
// and compiled function bodies (from JS_CompileFunction*). In practice, this
// means content scripts and event handlers. It'd be nice to stop there and
// simply stub out requests for source on chrome code. Life is not so easy,
// unfortunately. Nobody relies on chrome toSource() working in core browser
// code, but chrome tests use it. The worst offenders are addons, which like
// to monkeypatch chrome functions by calling toSource() on them and using
// regular expression to modify them. So, even though we don't keep it in
// memory, we have to provide a way to get chrome source somehow. Enter
// SourceHook. When the JS engine is asked to provide the source for a
// function it doesn't have in memory, it calls this function to load it.
mDefaultJSOptions |= JSOPTION_ONLY_CNG_SOURCE;
mContext = ::JS_NewContext(aRuntime, gStackSize);
if (mContext) {
::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
@ -1555,7 +1540,8 @@ nsJSContext::CompileScript(const PRUnichar* aText,
const char *aURL,
PRUint32 aLineNo,
PRUint32 aVersion,
nsScriptObjectHolder<JSScript>& aScriptObject)
nsScriptObjectHolder<JSScript>& aScriptObject,
bool aSaveSource /* = false */)
{
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
@ -1582,15 +1568,20 @@ nsJSContext::CompileScript(const PRUnichar* aText,
XPCAutoRequest ar(mContext);
JSScript* script =
::JS_CompileUCScriptForPrincipalsVersion(mContext,
scopeObject,
nsJSPrincipals::get(aPrincipal),
static_cast<const jschar*>(aText),
aTextLength,
aURL,
aLineNo,
JSVersion(aVersion));
JS::CompileOptions options(mContext);
JS::CompileOptions::SourcePolicy sp = aSaveSource ?
JS::CompileOptions::SAVE_SOURCE :
JS::CompileOptions::LAZY_SOURCE;
options.setPrincipals(nsJSPrincipals::get(aPrincipal))
.setFileAndLine(aURL, aLineNo)
.setVersion(JSVersion(aVersion))
.setSourcePolicy(sp);
JS::RootedObject rootedScope(mContext, scopeObject);
JSScript* script = JS::Compile(mContext,
rootedScope,
options,
static_cast<const jschar*>(aText),
aTextLength);
if (!script) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -3944,8 +3935,7 @@ ReadSourceFromFilename(JSContext *cx, const char *filename, jschar **src, PRUint
/*
The JS engine calls this function when it needs the source for a chrome JS
function. See the comment in nsJSContext::nsJSContext about
JSOPTION_ONLY_CGN_SOURCE.
function. See the comment in nsJSRuntime::Init().
*/
static bool
SourceHook(JSContext *cx, JSScript *script, jschar **src, uint32_t *length)
@ -3992,6 +3982,22 @@ nsJSRuntime::Init()
rv = sRuntimeService->GetRuntime(&sRuntime);
NS_ENSURE_SUCCESS(rv, rv);
// The JS engine needs to keep the source code around in order to implement
// Function.prototype.toSource(). It'd be nice to not have to do this for
// chrome code and simply stub out requests for source on it. Life is not so
// easy, unfortunately. Nobody relies on chrome toSource() working in core
// browser code, but chrome tests use it. The worst offenders are addons,
// which like to monkeypatch chrome functions by calling toSource() on them
// and using regular expressions to modify them. We avoid keeping most browser
// JS source code in memory by setting LAZY_SOURCE on JS::CompileOptions when
// compiling some chrome code. This causes the JS engine not save the source
// code in memory. When the JS engine is asked to provide the source for a
// function compiled with LAZY_SOURCE, it calls SourceHook to load it.
///
// Note we do have to retain the source code in memory for scripts compiled in
// compileAndGo mode and compiled function bodies (from
// JS_CompileFunction*). In practice, this means content scripts and event
// handlers.
JS_SetSourceHook(sRuntime, SourceHook);
// Let's make sure that our main thread is the same as the xpcom main thread.

View File

@ -72,7 +72,8 @@ public:
const char *aURL,
PRUint32 aLineNo,
PRUint32 aVersion,
nsScriptObjectHolder<JSScript>& aScriptObject);
nsScriptObjectHolder<JSScript>& aScriptObject,
bool aSaveSource = false);
virtual nsresult ExecuteScript(JSScript* aScriptObject,
JSObject* aScopeObject,
nsAString* aRetValue,

View File

@ -738,8 +738,15 @@ mozJSComponentLoader::GlobalForLocation(nsIFile *aComponentFile,
// any exceptions out to our caller. Ensure that the engine doesn't
// eagerly report the exception.
uint32_t oldopts = JS_GetOptions(cx);
JS_SetOptions(cx, oldopts | JSOPTION_NO_SCRIPT_RVAL |
(exception ? JSOPTION_DONT_REPORT_UNCAUGHT : 0));
if (exception)
JS_SetOptions(cx, oldopts | JSOPTION_DONT_REPORT_UNCAUGHT);
JS::CompileOptions options(cx);
options.setPrincipals(nsJSPrincipals::get(mSystemPrincipal))
.setNoScriptRval(true)
.setVersion(JSVERSION_LATEST)
.setFileAndLine(nativePath.get(), 1)
.setSourcePolicy(JS::CompileOptions::LAZY_SOURCE);
JS::RootedObject rootedGlobal(cx, global);
if (realFile) {
#ifdef HAVE_PR_MEMMAP
@ -789,10 +796,7 @@ mozJSComponentLoader::GlobalForLocation(nsIFile *aComponentFile,
return NS_ERROR_FAILURE;
}
script = JS_CompileScriptForPrincipalsVersion(cx, global,
nsJSPrincipals::get(mSystemPrincipal),
buf, fileSize32, nativePath.get(), 1,
JSVERSION_LATEST);
script = JS::Compile(cx, rootedGlobal, options, buf, fileSize32);
PR_MemUnmap(buf, fileSize32);
@ -834,10 +838,7 @@ mozJSComponentLoader::GlobalForLocation(nsIFile *aComponentFile,
NS_WARNING("Failed to read file");
return NS_ERROR_FAILURE;
}
script = JS_CompileScriptForPrincipalsVersion(cx, global,
nsJSPrincipals::get(mSystemPrincipal),
buf, rlen, nativePath.get(), 1,
JSVERSION_LATEST);
script = JS::Compile(cx, rootedGlobal, options, buf, rlen);
free(buf);
@ -873,10 +874,7 @@ mozJSComponentLoader::GlobalForLocation(nsIFile *aComponentFile,
buf[len] = '\0';
script = JS_CompileScriptForPrincipalsVersion(cx, global,
nsJSPrincipals::get(mSystemPrincipal),
buf, bytesRead, nativePath.get(), 1,
JSVERSION_LATEST);
script = JS::Compile(cx, rootedGlobal, options, buf, bytesRead);
}
// Propagate the exception, if one exists. Also, don't leave the stale
// exception on this context.

View File

@ -109,6 +109,11 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_ob
* exceptions, including the source/line number */
er = JS_SetErrorReporter(cx, mozJSLoaderErrorReporter);
JS::CompileOptions options(cx);
options.setPrincipals(nsJSPrincipals::get(principal))
.setFileAndLine(uriStr, 1)
.setSourcePolicy(JS::CompileOptions::LAZY_SOURCE);
JS::RootedObject target_obj_root(cx, target_obj);
if (!charset.IsVoid()) {
nsString script;
rv = nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const PRUint8*>(buf.get()), len,
@ -118,13 +123,10 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_ob
return ReportError(cx, LOAD_ERROR_BADCHARSET);
}
*scriptp =
JS_CompileUCScriptForPrincipals(cx, target_obj, nsJSPrincipals::get(principal),
reinterpret_cast<const jschar*>(script.get()),
script.Length(), uriStr, 1);
*scriptp = JS::Compile(cx, target_obj_root, options,
reinterpret_cast<const jschar*>(script.get()), script.Length());
} else {
*scriptp = JS_CompileScriptForPrincipals(cx, target_obj, nsJSPrincipals::get(principal),
buf.get(), len, uriStr, 1);
*scriptp = JS::Compile(cx, target_obj_root, options, buf.get(), len);
}
/* repent for our evil deeds */