Bug 679939 part 2. Disallow execution of global/eval scripts that are flagged runOnce and have already run. r=luke

This commit is contained in:
Boris Zbarsky 2015-04-01 12:05:28 -04:00
parent bbd4f124f2
commit 8886be1f58
3 changed files with 26 additions and 5 deletions

View File

@ -613,11 +613,19 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
MOZ_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
MOZ_ASSERT(script->functionNonDelazifying() == fun);
if (!fun && script->treatAsRunOnce() && script->hasRunOnce()) {
JS_ReportError(cx,
"Can't serialize a run-once non-function script "
"that has already run");
return false;
if (!fun && script->treatAsRunOnce()) {
// This is a toplevel or eval script that's runOnce. We want to
// make sure that we're not XDR-saving an object we emitted for
// JSOP_OBJECT that then got modified. So throw if we're not
// cloning in JSOP_OBJECT or if we ever didn't clone in it in the
// past.
const JS::CompartmentOptions& opts = JS::CompartmentOptionsRef(cx);
if (!opts.cloneSingletons() || !opts.getSingletonsAsTemplates()) {
JS_ReportError(cx,
"Can't serialize a run-once non-function script "
"when we're not doing singleton cloning");
return false;
}
}
nargs = script->bindings.numArgs();

View File

@ -1206,6 +1206,10 @@ class JSScript : public js::gc::TenuredCell
MOZ_ASSERT(isActiveEval() && !isCachedEval());
isActiveEval_ = false;
isCachedEval_ = true;
// IsEvalCacheCandidate will make sure that there's nothing in this
// script that would prevent reexecution even if isRunOnce is
// true. So just pretend like we never ran this script.
hasRunOnce_ = false;
}
void uncacheForEval() {

View File

@ -854,6 +854,15 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg, c
script->hasPollutedGlobalScope());
#endif
if (script->treatAsRunOnce()) {
if (script->hasRunOnce()) {
JS_ReportError(cx, "Trying to execute a run-once script multiple times");
return false;
}
script->setHasRunOnce();
}
if (script->isEmpty()) {
if (result)
result->setUndefined();