mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 883623 - Check free variables within eval'ed code before restarting processing of top level statements in the eval.
This commit is contained in:
parent
9002dd84b5
commit
aebd81764e
@ -76,6 +76,52 @@ CheckArgumentsWithinEval(JSContext *cx, Parser<FullParseHandler> &parser, Handle
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
MaybeCheckEvalFreeVariables(JSContext *cx, HandleScript evalCaller, HandleObject scopeChain,
|
||||||
|
Parser<FullParseHandler> &parser,
|
||||||
|
ParseContext<FullParseHandler> &pc)
|
||||||
|
{
|
||||||
|
if (!evalCaller || !evalCaller->functionOrCallerFunction())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Watch for uses of 'arguments' within the evaluated script, both as
|
||||||
|
// free variables and as variables redeclared with 'var'.
|
||||||
|
RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
|
||||||
|
HandlePropertyName arguments = cx->names().arguments;
|
||||||
|
for (AtomDefnRange r = pc.lexdeps->all(); !r.empty(); r.popFront()) {
|
||||||
|
if (r.front().key() == arguments) {
|
||||||
|
if (!CheckArgumentsWithinEval(cx, parser, fun))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (AtomDefnListMap::Range r = pc.decls().all(); !r.empty(); r.popFront()) {
|
||||||
|
if (r.front().key() == arguments) {
|
||||||
|
if (!CheckArgumentsWithinEval(cx, parser, fun))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the eval'ed script contains any debugger statement, force construction
|
||||||
|
// of arguments objects for the caller script and any other scripts it is
|
||||||
|
// transitively nested inside. The debugger can access any variable on the
|
||||||
|
// scope chain.
|
||||||
|
if (pc.sc->hasDebuggerStatement()) {
|
||||||
|
RootedObject scope(cx, scopeChain);
|
||||||
|
while (scope->isScope() || scope->isDebugScope()) {
|
||||||
|
if (scope->isCall() && !scope->asCall().isForEval()) {
|
||||||
|
RootedScript script(cx, scope->asCall().callee().nonLazyScript());
|
||||||
|
if (script->argumentsHasVarBinding()) {
|
||||||
|
if (!JSScript::argumentsOptimizationFailed(cx, script))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope = scope->enclosingScope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
CanLazilyParse(JSContext *cx, const CompileOptions &options)
|
CanLazilyParse(JSContext *cx, const CompileOptions &options)
|
||||||
{
|
{
|
||||||
@ -235,6 +281,12 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
|||||||
// be ambiguous.
|
// be ambiguous.
|
||||||
parser.clearAbortedSyntaxParse();
|
parser.clearAbortedSyntaxParse();
|
||||||
parser.tokenStream.seek(pos);
|
parser.tokenStream.seek(pos);
|
||||||
|
|
||||||
|
// Destroying the parse context will destroy its free
|
||||||
|
// variables, so check if any deoptimization is needed.
|
||||||
|
if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, pc.ref()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
pc.destroy();
|
pc.destroy();
|
||||||
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc,
|
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc,
|
||||||
staticLevel, /* bodyid = */ 0);
|
staticLevel, /* bodyid = */ 0);
|
||||||
@ -265,44 +317,11 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
|||||||
parser.handler.freeTree(pn);
|
parser.handler.freeTree(pn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetSourceMap(cx, parser.tokenStream, ss, script))
|
if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, pc.ref()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (evalCaller && evalCaller->functionOrCallerFunction()) {
|
if (!SetSourceMap(cx, parser.tokenStream, ss, script))
|
||||||
// Watch for uses of 'arguments' within the evaluated script, both as
|
return NULL;
|
||||||
// free variables and as variables redeclared with 'var'.
|
|
||||||
RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
|
|
||||||
HandlePropertyName arguments = cx->names().arguments;
|
|
||||||
for (AtomDefnRange r = pc.ref().lexdeps->all(); !r.empty(); r.popFront()) {
|
|
||||||
if (r.front().key() == arguments) {
|
|
||||||
if (!CheckArgumentsWithinEval(cx, parser, fun))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (AtomDefnListMap::Range r = pc.ref().decls().all(); !r.empty(); r.popFront()) {
|
|
||||||
if (r.front().key() == arguments) {
|
|
||||||
if (!CheckArgumentsWithinEval(cx, parser, fun))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the eval'ed script contains any debugger statement, force construction
|
|
||||||
// of arguments objects for the caller script and any other scripts it is
|
|
||||||
// transitively nested inside.
|
|
||||||
if (pc.ref().sc->hasDebuggerStatement()) {
|
|
||||||
RootedObject scope(cx, scopeChain);
|
|
||||||
while (scope->isScope() || scope->isDebugScope()) {
|
|
||||||
if (scope->isCall() && !scope->asCall().isForEval()) {
|
|
||||||
RootedScript script(cx, scope->asCall().callee().nonLazyScript());
|
|
||||||
if (script->argumentsHasVarBinding()) {
|
|
||||||
if (!JSScript::argumentsOptimizationFailed(cx, script))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope = scope->enclosingScope();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nowadays the threaded interpreter needs a stop instruction, so we
|
* Nowadays the threaded interpreter needs a stop instruction, so we
|
||||||
|
7
js/src/jit-test/tests/basic/bug883623.js
Normal file
7
js/src/jit-test/tests/basic/bug883623.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
(function() {
|
||||||
|
eval("\
|
||||||
|
arguments.valueOf();\
|
||||||
|
with (function(){}){};\
|
||||||
|
");
|
||||||
|
})()
|
Loading…
Reference in New Issue
Block a user