Bug 1097987 part 6. Require callers of JS_ExecuteScript to either use the global as the scope or pass in an explicit scopechain. r=waldo

This commit is contained in:
Boris Zbarsky 2015-03-14 01:36:16 -04:00
parent 5ac546abf3
commit d1e4959752
10 changed files with 67 additions and 56 deletions

View File

@ -177,7 +177,7 @@ Load(JSContext *cx,
if (!ok)
return false;
if (!JS_ExecuteScript(cx, obj, script)) {
if (!JS_ExecuteScript(cx, script)) {
return false;
}
}
@ -342,7 +342,7 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
.setFileAndLine(filename, 1);
JS::Rooted<JSScript*> script(cx);
if (JS::Compile(cx, global, options, file, &script))
(void)JS_ExecuteScript(cx, global, script, &result);
(void)JS_ExecuteScript(cx, script, &result);
return;
}
@ -379,7 +379,7 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
&script)) {
JSErrorReporter older;
ok = JS_ExecuteScript(cx, global, script, &result);
ok = JS_ExecuteScript(cx, script, &result);
if (ok && result != JSVAL_VOID) {
/* Suppress error reports from JS::ToString(). */
older = JS_SetErrorReporter(JS_GetRuntime(cx), nullptr);
@ -603,7 +603,7 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
}
JS::Rooted<JS::Value> result(cx);
bool ok = JS_ExecuteScript(cx, global, script, &result);
bool ok = JS_ExecuteScript(cx, script, &result);
if (ok && result != JSVAL_VOID) {
JSErrorReporter old = JS_SetErrorReporter(JS_GetRuntime(cx), nullptr);
JSString* str = JS::ToString(cx, result);

View File

@ -18,7 +18,7 @@ struct ScriptObjectFixture : public JSAPITest {
uc_code[i] = code[i];
}
bool tryScript(JS::HandleObject global, JS::HandleScript script)
bool tryScript(JS::HandleScript script)
{
CHECK(script);
@ -26,7 +26,7 @@ struct ScriptObjectFixture : public JSAPITest {
/* After a garbage collection, the script should still work. */
JS::RootedValue result(cx);
CHECK(JS_ExecuteScript(cx, global, script, &result));
CHECK(JS_ExecuteScript(cx, script, &result));
return true;
}
@ -43,7 +43,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, code, code_size, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
@ -53,7 +53,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, "", 0, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
@ -63,7 +63,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, code, code_size, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
@ -73,7 +73,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, code_size, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
@ -83,7 +83,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, 0, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
@ -93,7 +93,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipal
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, code_size, options, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals)
@ -109,7 +109,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile)
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_filename, &script));
tempScript.remove();
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile)
@ -124,7 +124,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty)
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_filename, &script));
tempScript.remove();
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty)
@ -139,7 +139,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle)
options.setFileAndLine(script_filename, 1);
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle)
@ -152,7 +152,7 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty)
options.setFileAndLine(script_filename, 1);
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty)
@ -166,6 +166,6 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincip
options.setFileAndLine("temporary file", 1);
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
return tryScript(script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincipals)

View File

@ -57,7 +57,7 @@ BEGIN_TEST(testXDR_bug506491)
// execute
JS::RootedValue v2(cx);
CHECK(JS_ExecuteScript(cx, global, script, &v2));
CHECK(JS_ExecuteScript(cx, script, &v2));
// try to break the Block object that is the parent of f
JS_GC(rt);
@ -83,7 +83,7 @@ BEGIN_TEST(testXDR_bug516827)
CHECK(script);
// execute with null result meaning no result wanted
CHECK(JS_ExecuteScript(cx, global, script));
CHECK(JS_ExecuteScript(cx, script));
return true;
}
END_TEST(testXDR_bug516827)

View File

@ -4115,15 +4115,15 @@ ExecuteScript(JSContext *cx, AutoObjectVector &scopeChain, HandleScript scriptAr
}
MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, MutableHandleValue rval)
JS_ExecuteScript(JSContext *cx, HandleScript scriptArg, MutableHandleValue rval)
{
return ExecuteScript(cx, obj, scriptArg, rval.address());
return ExecuteScript(cx, cx->global(), scriptArg, rval.address());
}
MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg)
JS_ExecuteScript(JSContext *cx, HandleScript scriptArg)
{
return ExecuteScript(cx, obj, scriptArg, nullptr);
return ExecuteScript(cx, cx->global(), scriptArg, nullptr);
}
MOZ_NEVER_INLINE JS_PUBLIC_API(bool)

View File

@ -3699,29 +3699,29 @@ extern JS_PUBLIC_API(JSString *)
JS_DecompileFunctionBody(JSContext *cx, JS::Handle<JSFunction*> fun, unsigned indent);
/*
* NB: JS_ExecuteScript and the JS::Evaluate APIs use the obj
* parameter as the initial scope chain header, the 'this' keyword value, and
* the variables object (ECMA parlance for where 'var' and 'function' bind
* names) of the execution context for script.
* NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either
* they use the global as the scope, or they take an AutoObjectVector of objects
* to use as the scope chain. In the former case, the global is also used as
* the "this" keyword value and the variables object (ECMA parlance for where
* 'var' and 'function' bind names) of the execution context for script. In the
* latter case, the first object in the provided list is used, unless the list
* is empty, in which case the global is used.
*
* Using obj as the variables object is problematic if obj's parent (which is
* the scope chain link) is not null, which in practice is always true: in
* this case, variables created by 'var x = 0', e.g., go in obj, but variables
* created by assignment to an unbound id, 'x = 0', go in the last object on
* the scope chain linked by parent.
* Using a non-global object as the variables object is problematic: in this
* case, variables created by 'var x = 0', e.g., go in that object, but
* variables created by assignment to an unbound id, 'x = 0', go in the global.
*
* ECMA calls that last scoping object the "global object", but note that many
* embeddings have several such objects. ECMA requires that "global code" be
* executed with the variables object equal to this global object. But these
* JS API entry points provide freedom to execute code against a "sub-global",
* i.e., a parented or scoped object, in which case the variables object will
* differ from the last object on the scope chain, resulting in confusing and
* non-ECMA explicit vs. implicit variable creation.
* ECMA requires that "global code" be executed with the variables object equal
* to the global object. But these JS API entry points provide freedom to
* execute code against a "sub-global", i.e., a parented or scoped object, in
* which case the variables object will differ from the global, resulting in
* confusing and non-ECMA explicit vs. implicit variable creation.
*
* Caveat embedders: unless you already depend on this buggy variables object
* binding behavior, you should call RuntimeOptionsRef(rt).setVarObjFix(true)
* for each context in the application, if you pass parented objects as the obj
* parameter, or may ever pass such objects in the future.
* for each context in the application, if you use the versions of
* JS_ExecuteScript and JS::Evaluate that take a scope chain argument, or may
* ever use them in the future.
*
* Why a runtime option? The alternative is to add APIs duplicating those below
* for the other value of varobjfix, and that doesn't seem worth the code bloat
@ -3730,16 +3730,20 @@ JS_DecompileFunctionBody(JSContext *cx, JS::Handle<JSFunction*> fun, unsigned in
* more easily hacked into existing code that does not depend on the bug; such
* code can continue to use the familiar JS::Evaluate, etc., entry points.
*/
/*
* Evaluate a script in the scope of the current global of cx.
*/
extern JS_PUBLIC_API(bool)
JS_ExecuteScript(JSContext *cx, JS::HandleObject obj, JS::HandleScript script, JS::MutableHandleValue rval);
JS_ExecuteScript(JSContext *cx, JS::HandleScript script, JS::MutableHandleValue rval);
extern JS_PUBLIC_API(bool)
JS_ExecuteScript(JSContext *cx, JS::HandleObject obj, JS::HandleScript script);
JS_ExecuteScript(JSContext *cx, JS::HandleScript script);
/*
* As above, but providing an explicit scope chain. scopeChain must not include
* the global object on it; that's implicit. It needs to contain the other
* objects that should end up on the scripts's scope chain.
* objects that should end up on the script's scope chain.
*/
extern JS_PUBLIC_API(bool)
JS_ExecuteScript(JSContext *cx, JS::AutoObjectVector &scopeChain,

View File

@ -463,7 +463,7 @@ RunFile(JSContext *cx, const char *filename, FILE *file, bool compileOnly)
AnalyzeEntrainedVariables(cx, script);
#endif
if (script && !compileOnly) {
if (!JS_ExecuteScript(cx, cx->global(), script)) {
if (!JS_ExecuteScript(cx, script)) {
if (!gQuitting && gExitCode != EXITCODE_TIMEOUT)
gExitCode = EXITCODE_RUNTIME_ERROR;
}
@ -489,7 +489,7 @@ EvalAndPrint(JSContext *cx, const char *bytes, size_t length,
if (compileOnly)
return true;
RootedValue result(cx);
if (!JS_ExecuteScript(cx, cx->global(), script, &result))
if (!JS_ExecuteScript(cx, script, &result))
return false;
if (!result.isUndefined()) {
@ -1327,7 +1327,7 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp)
if (!script->scriptSource()->setSourceMapURL(cx, smurl))
return false;
}
if (!JS_ExecuteScript(cx, global, script, args.rval())) {
if (!JS_ExecuteScript(cx, script, args.rval())) {
if (catchTermination && !JS_IsExceptionPending(cx)) {
JSAutoCompartment ac1(cx, callerGlobal);
JSString *str = JS_NewStringCopyZ(cx, "terminated");
@ -1493,7 +1493,7 @@ Run(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
if (!JS_ExecuteScript(cx, cx->global(), script))
if (!JS_ExecuteScript(cx, script))
return false;
int64_t endClock = PRMJ_Now();
@ -2819,7 +2819,7 @@ WorkerMain(void *arg)
if (!JS::Compile(cx, global, options, input->chars, input->length, &script))
break;
RootedValue result(cx);
JS_ExecuteScript(cx, global, script, &result);
JS_ExecuteScript(cx, script, &result);
} while (0);
JS::SetLargeAllocationFailureCallback(rt, nullptr, nullptr);
@ -3561,7 +3561,7 @@ runOffThreadScript(JSContext *cx, unsigned argc, jsval *vp)
if (!script)
return false;
return JS_ExecuteScript(cx, cx->global(), script, args.rval());
return JS_ExecuteScript(cx, script, args.rval());
}
struct FreeOnReturn

View File

@ -671,6 +671,7 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo &aInfo,
RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
mReuseLoaderGlobal, &realFile));
NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
MOZ_ASSERT(JS_IsGlobalObject(obj) == !mReuseLoaderGlobal);
JSAutoCompartment ac(cx, obj);
@ -898,6 +899,12 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo &aInfo,
return NS_ERROR_FAILURE;
}
// We must have a script or a function (but not both!) here. We have a
// script when we're not reusing the loader global, and a function
// otherwise.
MOZ_ASSERT(!!script != !!function);
MOZ_ASSERT(!!script == JS_IsGlobalObject(obj));
if (writeToCache) {
// We successfully compiled the script, so cache it.
if (script) {
@ -940,7 +947,7 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo &aInfo,
if (aPropagateExceptions)
ContextOptionsRef(cx).setDontReportUncaught(true);
if (script) {
ok = JS_ExecuteScript(cx, obj, script);
ok = JS_ExecuteScript(cx, script);
} else {
RootedValue rval(cx);
ok = JS_CallFunction(cx, obj, function, JS::HandleValueArray::empty(), &rval);

View File

@ -379,7 +379,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url,
retval);
} else {
if (JS_IsGlobalObject(targetObj)) {
ok = JS_ExecuteScript(cx, targetObj, script, retval);
ok = JS_ExecuteScript(cx, script, retval);
} else {
JS::AutoObjectVector scopeChain(cx);
ok = scopeChain.append(targetObj) &&

View File

@ -345,7 +345,7 @@ Load(JSContext *cx, unsigned argc, jsval *vp)
if (!compileOnly) {
// XXXbz are we intentionally allowing load.call(someNonGlobalObject)?
if (JS_IsGlobalObject(obj)) {
if (!JS_ExecuteScript(cx, obj, script)) {
if (!JS_ExecuteScript(cx, script)) {
return false;
}
} else {
@ -838,7 +838,7 @@ ProcessFile(JSContext *cx, const char *filename, FILE *file, bool forceTTY)
.setFileAndLine(filename, 1)
.setCompileAndGo(true);
if (JS::Compile(cx, global, options, file, &script) && !compileOnly)
(void)JS_ExecuteScript(cx, global, script, &result);
(void)JS_ExecuteScript(cx, script, &result);
JS_EndRequest(cx);
return;
@ -878,7 +878,7 @@ ProcessFile(JSContext *cx, const char *filename, FILE *file, bool forceTTY)
JSErrorReporter older;
if (!compileOnly) {
ok = JS_ExecuteScript(cx, global, script, &result);
ok = JS_ExecuteScript(cx, script, &result);
if (ok && result != JSVAL_VOID) {
/* Suppress error reports from JS::ToString(). */
older = JS_SetErrorReporter(JS_GetRuntime(cx), nullptr);

View File

@ -668,7 +668,7 @@ ProxyAutoConfig::SetupJS()
JS::Rooted<JSScript*> script(cx);
if (!JS_CompileScript(cx, global, mPACScript.get(),
mPACScript.Length(), options, &script) ||
!JS_ExecuteScript(cx, global, script))
!JS_ExecuteScript(cx, script))
{
nsString alertMessage(NS_LITERAL_STRING("PAC file failed to install from "));
if (isDataURI) {