8026167: Class cache/reuse of 'eval' scripts results in ClassCastException in some cases

Reviewed-by: lagergren, jlaskey
This commit is contained in:
Athijegannathan Sundararajan 2013-10-10 11:48:56 +02:00
parent 16ce875fc6
commit d5dda0a437
26 changed files with 164 additions and 70 deletions

View File

@ -162,7 +162,7 @@ enum CompilationPhase {
LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) { LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) {
@Override @Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) { FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
return (FunctionNode)fn.accept(new Lower()); return (FunctionNode)fn.accept(new Lower(compiler));
} }
@Override @Override

View File

@ -86,10 +86,13 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
private static final DebugLogger LOG = new DebugLogger("lower"); private static final DebugLogger LOG = new DebugLogger("lower");
// needed only to get unique eval id from code installer
private final Compiler compiler;
/** /**
* Constructor. * Constructor.
*/ */
Lower() { Lower(final Compiler compiler) {
super(new BlockLexicalContext() { super(new BlockLexicalContext() {
@Override @Override
@ -132,6 +135,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
return block.setIsTerminal(this, false); return block.setIsTerminal(this, false);
} }
}); });
this.compiler = compiler;
} }
@Override @Override
@ -529,11 +533,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
*/ */
private String evalLocation(final IdentNode node) { private String evalLocation(final IdentNode node) {
final Source source = lc.getCurrentFunction().getSource(); final Source source = lc.getCurrentFunction().getSource();
final int pos = node.position();
return new StringBuilder(). return new StringBuilder().
append(source.getName()). append(source.getName()).
append('#'). append('#').
append(source.getLine(node.position())). append(source.getLine(pos)).
append("<eval>"). append(':').
append(source.getColumn(pos)).
append("<eval>@").
append(compiler.getCodeInstaller().getUniqueEvalId()).
toString(); toString();
} }

View File

@ -68,4 +68,10 @@ public interface CodeInstaller<T> {
* @return unique script id * @return unique script id
*/ */
public long getUniqueScriptId(); public long getUniqueScriptId();
/**
* Get next unique eval id
* @return unique eval id
*/
public long getUniqueEvalId();
} }

View File

@ -139,6 +139,11 @@ public final class Context {
public long getUniqueScriptId() { public long getUniqueScriptId() {
return context.getUniqueScriptId(); return context.getUniqueScriptId();
} }
@Override
public long getUniqueEvalId() {
return context.getUniqueEvalId();
}
} }
/** Is Context global debug mode enabled ? */ /** Is Context global debug mode enabled ? */
@ -238,6 +243,9 @@ public final class Context {
/** Unique id for script. Used only when --loader-per-compile=false */ /** Unique id for script. Used only when --loader-per-compile=false */
private final AtomicLong uniqueScriptId; private final AtomicLong uniqueScriptId;
/** Unique id for 'eval' */
private final AtomicLong uniqueEvalId;
private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader; private static final StructureLoader sharedLoader;
@ -320,6 +328,7 @@ public final class Context {
this.uniqueScriptId = new AtomicLong(); this.uniqueScriptId = new AtomicLong();
} }
this.errors = errors; this.errors = errors;
this.uniqueEvalId = new AtomicLong();
// if user passed -classpath option, make a class loader with that and set it as // if user passed -classpath option, make a class loader with that and set it as
// thread context class loader so that script can access classes from that path. // thread context class loader so that script can access classes from that path.
@ -954,6 +963,10 @@ public final class Context {
}, CREATE_LOADER_ACC_CTXT); }, CREATE_LOADER_ACC_CTXT);
} }
private long getUniqueEvalId() {
return uniqueEvalId.getAndIncrement();
}
private long getUniqueScriptId() { private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement(); return uniqueScriptId.getAndIncrement();
} }

View File

@ -61,3 +61,22 @@ Object.defineProperty(this, "fail", {
} }
} }
}); });
Object.defineProperty(this, "printError", {
configuable: true,
enumerable: false,
writable: true,
value: function (e) {
var msg = e.message;
var str = e.name + ':';
if (e.lineNumber > 0) {
str += e.lineNumber + ':';
}
if (e.columnNumber > 0) {
str += e.columnNumber + ':';
}
str += msg.substring(msg.indexOf(' ') + 1);
print(str);
}
});

View File

@ -36,7 +36,7 @@ function checkObjLiteral(str) {
if (! (e instanceof SyntaxError)) { if (! (e instanceof SyntaxError)) {
fail("expected SyntaxError, got " + e); fail("expected SyntaxError, got " + e);
} }
print(e.message.replace(/\\/g, '/')); printError(e);
} }
} }

View File

@ -1,12 +1,12 @@
test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found , SyntaxError:33:Expected property id but found ,
({,}) ({,})
^ ^
test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found , SyntaxError:33:Expected property id but found ,
({, a:2 }) ({, a:2 })
^ ^
test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected property id but found , SyntaxError:33:Expected property id but found ,
({a:3,,}) ({a:3,,})
^ ^
test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected comma but found ident SyntaxError:33:Expected comma but found ident
({a:3 b:2} ({a:3 b:2}
^ ^

View File

@ -33,7 +33,7 @@ function check(str) {
eval(str); eval(str);
fail("SyntaxError expected for: " + str); fail("SyntaxError expected for: " + str);
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
} }

View File

@ -1,12 +1,12 @@
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found + SyntaxError:33:Expected l-value but found +
++ +3 ++ +3
^ ^
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found - SyntaxError:33:Expected l-value but found -
++ -7 ++ -7
^ ^
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found + SyntaxError:33:Expected l-value but found +
-- +2 -- +2
^ ^
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found - SyntaxError:33:Expected l-value but found -
-- -8 -- -8
^ ^

View File

@ -33,7 +33,7 @@ try {
eval('"" ~ ""'); eval('"" ~ ""');
print("FAILED: SyntaxError expected for: \"\" ~ \"\""); print("FAILED: SyntaxError expected for: \"\" ~ \"\"");
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
// Used to crash instead of SyntaxError // Used to crash instead of SyntaxError
@ -41,7 +41,7 @@ try {
eval("function() { if (1~0) return 0; return 1 }"); eval("function() { if (1~0) return 0; return 1 }");
print("FAILED: SyntaxError expected for: if (1~0) "); print("FAILED: SyntaxError expected for: if (1~0) ");
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
// The following are valid, but used to crash // The following are valid, but used to crash

View File

@ -1,6 +1,6 @@
SyntaxError: test/script/basic/JDK-8019791.js#33<eval>:1:3 Expected ; but found ~ SyntaxError:33:Expected ; but found ~
"" ~ "" "" ~ ""
^ ^
SyntaxError: test/script/basic/JDK-8019791.js#41<eval>:1:18 Expected ) but found ~ SyntaxError:41:Expected ) but found ~
function() { if (1~0) return 0; return 1 } function() { if (1~0) return 0; return 1 }
^ ^

View File

@ -32,5 +32,5 @@ try {
eval("for each(var v=0;false;);"); eval("for each(var v=0;false;);");
print("FAILED: for each(var v=0; false;); should have thrown error"); print("FAILED: for each(var v=0; false;); should have thrown error");
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }

View File

@ -1,3 +1,3 @@
SyntaxError: test/script/basic/JDK-8019805.js#32<eval>:1:16 for each can only be used with for..in SyntaxError:32:for each can only be used with for..in
for each(var v=0;false;); for each(var v=0;false;);
^ ^

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2010, 2013, 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-8026167: Class cache/reuse of 'eval' scripts results in ClassCastException in some cases.
*
* @test
* @run
*/
var m = new javax.script.ScriptEngineManager();
var e = m.getEngineByName('js');
// leave the whitespace - need both eval("e") at same column for this test!
e.eval('function f(e) { eval("e") } f()');
e.eval('function f() { var e = 33; eval("e") } f()');
function f() {
Function.call.call(function x() { eval("x") }); eval("x")
}
try {
f();
fail("Should have thrown ReferenceError");
} catch (e) {
if (! (e instanceof ReferenceError)) {
fail("ReferenceError expected but got " + e);
}
}

View File

@ -35,5 +35,5 @@ try {
if (! (e instanceof SyntaxError)) { if (! (e instanceof SyntaxError)) {
fail("#2 expected SyntaxError got " + e); fail("#2 expected SyntaxError got " + e);
} }
print(e.toString().replace(/\\/g, '/')); printError(e);
} }

View File

@ -1,3 +1,3 @@
SyntaxError: test/script/basic/NASHORN-100.js#32<eval>:1:0 Invalid return statement SyntaxError:32:Invalid return statement
return; return;
^ ^

View File

@ -40,15 +40,13 @@ for (var i = 0; i < 3; i++) {
try { try {
eval(src); eval(src);
} catch (e) { } catch (e) {
var location = e.fileName ? e.fileName.slice(-9) : "unknown source"; printError(e);
print(e.name, "@", location);
} }
} }
for (var i = 0; i < 3; i++) { for (var i = 0; i < 3; i++) {
try { try {
eval(src); eval(src);
} catch (e) { } catch (e) {
var location = e.fileName ? e.fileName.slice(-9) : "unknown source"; printError(e);
print(e.name, "@", location);
} }
} }

View File

@ -1,9 +1,9 @@
hello hello
hello hello
hello hello
TypeError @ #41<eval> TypeError:1:read property "foo" from undefined
TypeError @ #41<eval> TypeError:1:read property "foo" from undefined
TypeError @ #41<eval> TypeError:1:read property "foo" from undefined
TypeError @ #49<eval> TypeError:1:read property "foo" from undefined
TypeError @ #49<eval> TypeError:1:read property "foo" from undefined
TypeError @ #49<eval> TypeError:1:read property "foo" from undefined

View File

@ -31,11 +31,11 @@
try { try {
eval("print(.foo)"); eval("print(.foo)");
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
try { try {
eval(".bar = 3423;"); eval(".bar = 3423;");
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }

View File

@ -1,6 +1,6 @@
SyntaxError: test/script/basic/NASHORN-40.js#32<eval>:1:6 Expected an operand but found . SyntaxError:32:Expected an operand but found .
print(.foo) print(.foo)
^ ^
SyntaxError: test/script/basic/NASHORN-40.js#38<eval>:1:0 Expected an operand but found . SyntaxError:38:Expected an operand but found .
.bar = 3423; .bar = 3423;
^ ^

View File

@ -35,28 +35,28 @@ for (i in literals) {
eval(literals[i] + "++"); eval(literals[i] + "++");
print("ERROR!! post increment : " + literals[i]); print("ERROR!! post increment : " + literals[i]);
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
try { try {
eval(literals[i] + "--"); eval(literals[i] + "--");
print("ERROR!! post decrement : " + literals[i]); print("ERROR!! post decrement : " + literals[i]);
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
try { try {
eval("++" + literals[i]); eval("++" + literals[i]);
print("ERROR!! pre increment : " + literals[i]); print("ERROR!! pre increment : " + literals[i]);
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
try { try {
eval("--" + literals[i]); eval("--" + literals[i]);
print("ERROR!! pre decrement : " + literals[i]); print("ERROR!! pre decrement : " + literals[i]);
} catch (e) { } catch (e) {
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
} }

View File

@ -1,72 +1,72 @@
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
1++ 1++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
1-- 1--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++1 ++1
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--1 --1
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
0++ 0++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
0-- 0--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++0 ++0
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--0 --0
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
3.14++ 3.14++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
3.14-- 3.14--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++3.14 ++3.14
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--3.14 --3.14
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
true++ true++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
true-- true--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++true ++true
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--true --true
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
false++ false++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
false-- false--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++false ++false
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--false --false
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment ReferenceError:35:Invalid left hand side for assignment
null++ null++
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment ReferenceError:42:Invalid left hand side for assignment
null-- null--
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment ReferenceError:49:Invalid left hand side for assignment
++null ++null
^ ^
ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment ReferenceError:56:Invalid left hand side for assignment
--null --null
^ ^

View File

@ -34,7 +34,7 @@ try {
if (! (e instanceof SyntaxError)) { if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e); fail("syntax error expected here got " + e);
} }
print(e.toString().replace(/\\/g, '/')); printError(e);
} }
try { try {
@ -43,5 +43,5 @@ try {
if (! (e instanceof SyntaxError)) { if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e); fail("syntax error expected here got " + e);
} }
print(e.toString().replace(/\\/g, '/')); printError(e);
} }

View File

@ -1,6 +1,6 @@
SyntaxError: test/script/basic/NASHORN-98.js#32<eval>:1:13 Expected comma but found decimal SyntaxError:32:Expected comma but found decimal
var x = [ 23 34 ] var x = [ 23 34 ]
^ ^
SyntaxError: test/script/basic/NASHORN-98.js#41<eval>:1:18 Expected comma but found ident SyntaxError:41:Expected comma but found ident
var x = { foo: 33 bar: 'hello' } var x = { foo: 33 bar: 'hello' }
^ ^

View File

@ -69,5 +69,5 @@ try {
eval("print('hello)"); eval("print('hello)");
} catch (e) { } catch (e) {
print("is syntax error? " + (e instanceof SyntaxError)); print("is syntax error? " + (e instanceof SyntaxError));
print(e.toString().replace(/\\/g, '/')); printError(e);
} }

View File

@ -10,6 +10,6 @@ eval.length 1
100 100
3300 3300
is syntax error? true is syntax error? true
SyntaxError: test/script/basic/eval.js#69<eval>:1:13 Missing close quote SyntaxError:69:Missing close quote
print('hello) print('hello)
^ ^