8048071: eval within 'with' statement does not use correct scope if with scope expression has a copy of eval
Reviewed-by: hannesw, jlaskey
This commit is contained in:
parent
d983b0b09c
commit
dee1364e7c
@ -1290,13 +1290,26 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
int argsCount;
|
||||
@Override
|
||||
void loadStack() {
|
||||
loadExpressionAsObject(ident); // Type.OBJECT as foo() makes no sense if foo == 3
|
||||
method.dup();
|
||||
/**
|
||||
* We want to load 'eval' to check if it is indeed global builtin eval.
|
||||
* If this eval call is inside a 'with' statement, dyn:getMethod|getProp|getElem
|
||||
* would be generated if ident is a "isFunction". But, that would result in a
|
||||
* bound function from WithObject. We don't want that as bound function as that
|
||||
* won't be detected as builtin eval. So, we make ident as "not a function" which
|
||||
* results in "dyn:getProp|getElem|getMethod" being generated and so WithObject
|
||||
* would return unbounded eval function.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var global = this;
|
||||
* function func() {
|
||||
* with({ eval: global.eval) { eval("var x = 10;") }
|
||||
* }
|
||||
*/
|
||||
loadExpressionAsObject(ident.setIsNotFunction()); // Type.OBJECT as foo() makes no sense if foo == 3
|
||||
globalIsEval();
|
||||
method.ifeq(is_not_eval);
|
||||
|
||||
// We don't need ScriptFunction object for 'eval'
|
||||
method.pop();
|
||||
// Load up self (scope).
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
|
||||
@ -1316,6 +1329,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
method._goto(invoke_direct_eval);
|
||||
|
||||
method.label(is_not_eval);
|
||||
// load this time but with dyn:getMethod|getProp|getElem
|
||||
loadExpressionAsObject(ident); // Type.OBJECT as foo() makes no sense if foo == 3
|
||||
// This is some scope 'eval' or global eval replaced by user
|
||||
// but not the built-in ECMAScript 'eval' function call
|
||||
method.loadNull();
|
||||
|
@ -280,6 +280,17 @@ public final class IdentNode extends Expression implements PropertyKey, Function
|
||||
return new IdentNode(this, name, type, flags | FUNCTION, programPoint, conversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this node as not being the callee operand of a {@link CallNode}.
|
||||
* @return an ident node identical to this one in all aspects except with its function flag unset.
|
||||
*/
|
||||
public IdentNode setIsNotFunction() {
|
||||
if (! isFunction()) {
|
||||
return this;
|
||||
}
|
||||
return new IdentNode(this, name, type, flags & ~FUNCTION, programPoint, conversion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgramPoint() {
|
||||
return programPoint;
|
||||
|
85
nashorn/test/script/basic/JDK-8048071.js
Normal file
85
nashorn/test/script/basic/JDK-8048071.js
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8048071: eval within 'with' statement does not use correct scope if with scope expression has a copy of eval
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
function func() {
|
||||
var x = 1;
|
||||
with ({ eval: this.eval }) {
|
||||
eval("var x = 23");
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
print(func());
|
||||
print("typeof x? " + typeof x);
|
||||
|
||||
print((function(global){
|
||||
var x = 1;
|
||||
with(global) {
|
||||
eval("eval('var x=0')");
|
||||
}
|
||||
return x;
|
||||
})(this));
|
||||
print("typeof x? " + typeof x);
|
||||
|
||||
print((function(global){
|
||||
var x = 1;
|
||||
with({eval: global.eval}) {
|
||||
eval("eval('var x=0')");
|
||||
}
|
||||
return x;
|
||||
})(this));
|
||||
print("typeof x? " + typeof x);
|
||||
|
||||
// not-builtin eval cases
|
||||
|
||||
(function () {
|
||||
function eval(str) {
|
||||
print("local eval called: " + str);
|
||||
print(this);
|
||||
}
|
||||
|
||||
with({}) {
|
||||
eval("hello");
|
||||
}
|
||||
})();
|
||||
|
||||
(function () {
|
||||
with({
|
||||
eval:function(str) {
|
||||
print("with's eval called: " + str);
|
||||
print("this = " + this);
|
||||
print("this.foo = " + this.foo);
|
||||
},
|
||||
foo: 42
|
||||
}) {
|
||||
eval("hello")
|
||||
}
|
||||
})();
|
11
nashorn/test/script/basic/JDK-8048071.js.EXPECTED
Normal file
11
nashorn/test/script/basic/JDK-8048071.js.EXPECTED
Normal file
@ -0,0 +1,11 @@
|
||||
23
|
||||
typeof x? undefined
|
||||
0
|
||||
typeof x? undefined
|
||||
0
|
||||
typeof x? undefined
|
||||
local eval called: hello
|
||||
[object global]
|
||||
with's eval called: hello
|
||||
this = [object Object]
|
||||
this.foo = 42
|
Loading…
Reference in New Issue
Block a user