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)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
return (FunctionNode)fn.accept(new Lower());
return (FunctionNode)fn.accept(new Lower(compiler));
}
@Override

View File

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

View File

@ -68,4 +68,10 @@ public interface CodeInstaller<T> {
* @return unique script id
*/
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() {
return context.getUniqueScriptId();
}
@Override
public long getUniqueEvalId() {
return context.getUniqueEvalId();
}
}
/** 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 */
private final AtomicLong uniqueScriptId;
/** Unique id for 'eval' */
private final AtomicLong uniqueEvalId;
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
@ -320,6 +328,7 @@ public final class Context {
this.uniqueScriptId = new AtomicLong();
}
this.errors = errors;
this.uniqueEvalId = new AtomicLong();
// 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.
@ -954,6 +963,10 @@ public final class Context {
}, CREATE_LOADER_ACC_CTXT);
}
private long getUniqueEvalId() {
return uniqueEvalId.getAndIncrement();
}
private long getUniqueScriptId() {
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)) {
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 })
^
test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected property id but found ,
SyntaxError:33:Expected property id but found ,
({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}
^

View File

@ -33,7 +33,7 @@ function check(str) {
eval(str);
fail("SyntaxError expected for: " + str);
} 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
^
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
SyntaxError:33:Expected l-value but found -
++ -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
^
SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
SyntaxError:33:Expected l-value but found -
-- -8
^

View File

@ -33,7 +33,7 @@ try {
eval('"" ~ ""');
print("FAILED: SyntaxError expected for: \"\" ~ \"\"");
} catch (e) {
print(e.toString().replace(/\\/g, '/'));
printError(e);
}
// Used to crash instead of SyntaxError
@ -41,7 +41,7 @@ try {
eval("function() { if (1~0) return 0; return 1 }");
print("FAILED: SyntaxError expected for: if (1~0) ");
} catch (e) {
print(e.toString().replace(/\\/g, '/'));
printError(e);
}
// 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 }
^

View File

@ -32,5 +32,5 @@ try {
eval("for each(var v=0;false;);");
print("FAILED: for each(var v=0; false;); should have thrown error");
} 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;);
^

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)) {
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;
^

View File

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

View File

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

View File

@ -31,11 +31,11 @@
try {
eval("print(.foo)");
} catch (e) {
print(e.toString().replace(/\\/g, '/'));
printError(e);
}
try {
eval(".bar = 3423;");
} 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)
^
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;
^

View File

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

View File

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

View File

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

View File

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