Details
-
Bug
-
Status: Closed
-
Blocker
-
Resolution: Fixed
-
5.2
-
None
Description
BCELifier calls BCELFactory. The BCELFactory.createConstant method does not
handle floats and longs correctly:
private void createConstant( Object value ) {
String embed = value.toString();
if (value instanceof String)
_out.println("il.append(new PUSH(_cp, " + embed + "));");
}
Note that the types String and char are handled separately. As for the other
types, it's relying on there being an overloaded constructor of PUSH that takes
the constant in its correct form once it is converted to a String.
Let's examine all the other types:
- boolean: Boolean.toString() produces the values "true" and "false", which
javac picks up as booleans, e.g. "new PUSH(_cp, false)".
- byte, short, int: Integer.toString() produces valid values. In the
bytecode, there is no (significant) distinction between these types (except for
method signatures, fields, etc.).
- double: Double.toString() produces valid values, e.g. "new PUSH(_cp, 0.0)".
- float: Float.toString() produces values that look like doubles, e.g. "new
PUSH(_cp, 0.0)". These are mishandled.
- long: Long.toString() produces values that look like ints, e.g. "new
PUSH(_cp, 0)", or, even worse, "new PUSH(_cp, 4000000000)" (which doesn't
compile).
I've attached two simple test cases that illustrate the issues. Do the
following with
% javac TestIncorrectLiterals.java
% java TestIncorrectLiterals
% java org.apache.bcel.util.BCELifier TestIncorrectLiterals
>TestIncorrectLiteralsCreator.java
% javac TestIncorrectLiteralsCreator.java
% java TestIncorrectLiteralsCreator
% java TestIncorrectLiterals
Exception in thread "main" java.lang.VerifyError: (class:
TestIncorrectLiterals, method: main signature: ([Ljava/lang/String;)V)
Expecting to find float on stack
% javac TestOutOfRangeLiterals.java
% java TestOutOfRangeLiterals
% java org.apache.bcel.util.BCELifier TestOutOfRangeLiterals
>TestOutOfRangeLiteralsCreator.java
% javac TestOutOfRangeLiteralsCreator.java
TestOutOfRangeLiteralsCreator.java:41: integer number too large: 4000000000
InstructionHandle ih_0 = il.append(new PUSH(_cp, 4000000000));
^
1 error
Here's my suggested fix:
private void createConstant( Object value ) {
String embed = value.toString();
if (value instanceof String) { embed = '"' + Utility.convertString(embed) + '"'; }
else if (value instanceof Character)
{ embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); }else if (value instanceof Float)
{ embed += "f"; }else if (value instanceof Long)
{ embed += "L"; } _out.println("il.append(new PUSH(_cp, " + embed + "));");
}
I shall test out this fix, and report back.
This issue seems to exist in the SVN trunk code too.