-
Bug
-
Resolution: Fixed
-
P4
-
8
-
b01
-
linux
-
Verified
FULL PRODUCT VERSION :
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux 3.11.6-1-ck #1 SMP PREEMPT Fri Oct 18 16:25:57 EDT 2013 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When TreeMaker.Literal(Object) is invoked with an object of type Character, the resulting JCLiteral will throw a ClassCastException if its getValue method is called.
This problem may have been missed due to the existence of both a public `value` field on JCLiteral and a public, nontrivial, getValue method - this seems a strange thing to have.
The problem appears to be caused by the way TreeMaker.Literal(Object) handles objects of type Character:
public JCLiteral Literal(Object value) {
JCLiteral result = null;
if (value instanceof String) {
...*snip*...
} else if (value instanceof Character) {
int v = (int) (((Character) value).toString().charAt(0));
result = Literal(CHAR, value).
setType(syms.charType.constType(v));
} else if...
...*snip*...
return result;
}
It passes to the other Literal function the input object, 'value', of type Character, instead of the integer, 'v'.
This causes the resulting JCLiteral's value field to be of type Character and the typetag field to be CHAR.
Unfortunately, JCLiteral.getValue, when handling literals with a typetag of CHAR, casts the value field to type Integer - an invalid cast.
It appears the correct form for a JCLiteral for a character literal is to have a value of type Integer and a typetag of CHAR.
It seems, then, that all that is necessary to fix this problem is to replace the line in TreeMaker with:
result = Literal(CHAR, v).
setType(syms.charType.constType(v));
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Call getValue on a JCLiteral obtained via a call to TreeMaker.Literal(Object) (Not TreeMaker.Literal(TypeTag, Object)).
Observe the explosions.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A JCLiteral correctly describing a character literal.
ACTUAL -
A JCLiteral correctly describing a character literal that explodes when touched.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
A stack trace of the ensuing ClassCastException:
java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Integer
at com.sun.tools.javac.tree.JCTree$JCLiteral.getValue(JCTree.java:2043)
at TestExplodingLiterals(TestExplodingLiterals.java:19)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import javax.tools.JavaFileManager;
public class Explode {
public static TreeMaker treeMaker;
public static void main(String[] args) {
// Dirty hack to make this test case not have to be actually complicted...
Context context = new Context();
// Yes, yes, you'd never *actually* do this.
JavacFileManager fileManager = new JavacFileManager(context, true, null);
context.put(JavaFileManager.class, fileManager);
// The actual test case...
treeMaker = TreeMaker.instance(context);
// *Boom* - ClassCastException
treeMaker.Literal('a').getValue();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use of the other TreeMaker.Literal method passing typetag CHAR and a value of type Integer works correctly.
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux 3.11.6-1-ck #1 SMP PREEMPT Fri Oct 18 16:25:57 EDT 2013 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When TreeMaker.Literal(Object) is invoked with an object of type Character, the resulting JCLiteral will throw a ClassCastException if its getValue method is called.
This problem may have been missed due to the existence of both a public `value` field on JCLiteral and a public, nontrivial, getValue method - this seems a strange thing to have.
The problem appears to be caused by the way TreeMaker.Literal(Object) handles objects of type Character:
public JCLiteral Literal(Object value) {
JCLiteral result = null;
if (value instanceof String) {
...*snip*...
} else if (value instanceof Character) {
int v = (int) (((Character) value).toString().charAt(0));
result = Literal(CHAR, value).
setType(syms.charType.constType(v));
} else if...
...*snip*...
return result;
}
It passes to the other Literal function the input object, 'value', of type Character, instead of the integer, 'v'.
This causes the resulting JCLiteral's value field to be of type Character and the typetag field to be CHAR.
Unfortunately, JCLiteral.getValue, when handling literals with a typetag of CHAR, casts the value field to type Integer - an invalid cast.
It appears the correct form for a JCLiteral for a character literal is to have a value of type Integer and a typetag of CHAR.
It seems, then, that all that is necessary to fix this problem is to replace the line in TreeMaker with:
result = Literal(CHAR, v).
setType(syms.charType.constType(v));
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Call getValue on a JCLiteral obtained via a call to TreeMaker.Literal(Object) (Not TreeMaker.Literal(TypeTag, Object)).
Observe the explosions.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A JCLiteral correctly describing a character literal.
ACTUAL -
A JCLiteral correctly describing a character literal that explodes when touched.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
A stack trace of the ensuing ClassCastException:
java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Integer
at com.sun.tools.javac.tree.JCTree$JCLiteral.getValue(JCTree.java:2043)
at TestExplodingLiterals(TestExplodingLiterals.java:19)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import javax.tools.JavaFileManager;
public class Explode {
public static TreeMaker treeMaker;
public static void main(String[] args) {
// Dirty hack to make this test case not have to be actually complicted...
Context context = new Context();
// Yes, yes, you'd never *actually* do this.
JavacFileManager fileManager = new JavacFileManager(context, true, null);
context.put(JavaFileManager.class, fileManager);
// The actual test case...
treeMaker = TreeMaker.instance(context);
// *Boom* - ClassCastException
treeMaker.Literal('a').getValue();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use of the other TreeMaker.Literal method passing typetag CHAR and a value of type Integer works correctly.
- duplicates
-
JDK-8041708 java.lang.ClassCastException: com.sun.tools.javac.tree.JCTree$JCLiteral cannot b
-
- Closed
-