JDK-6614974 : javac successfully compiles code that throws java.lang.VerifyError when run
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6,6u26
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,windows_xp
  • CPU: x86
  • Submitted: 2007-10-10
  • Updated: 2011-09-20
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
JDK 7
7 b25Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b06)
Java HotSpot(TM) Client VM (build 1.6.0_02-b06, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
The following code compiles successfully with javac:

public class BugReport<T> {

	private T n;

	public void error() {
		BugReport<Integer> val = new BugReport<Integer>();
		val.n = 0;
		Integer.toString(val.n++);
	}

	public static void main(String[] args) {
		BugReport.class.getMethods();
	}
}

However, when run with `java BugReport', it always throws the following error:

Exception in thread "main" java.lang.VerifyError: (class: BugReport, method: error signature: ()V) Incompatible object argument for function call

This is likely due to the generics/autoboxing combination that fails in this case at the line Integer.toString(val.n++).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the code from the description and run it.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No error.
ACTUAL -
This error:

Exception in thread "main" java.lang.VerifyError: (class: BugReport, method: error signature: ()V) Incompatible object argument for function call

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.VerifyError: (class: BugReport, method: error signature: ()V) Incompatible object argument for function call

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class BugReport<T> {

	private T n;

	public void error() {
		BugReport<Integer> val = new BugReport<Integer>();
		val.n = 0;
		Integer.toString(val.n++);
	}

	public static void main(String[] args) {
		BugReport.class.getMethods();
	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
val.n++ can be moved out of the method call and the call itself can be changed to Integer.toString(val.n).

Comments
EVALUATION Autoboxing is implemented by javac by means of LetExpr nodes of AST of the kind let int v = i.intValue in ...; //where i is a variable whose type is Integer However, when the compiler generates those LetExpr nodes, a synthetic cast should be added if the type of the right handed expression is a type variable as described in the example: let int v = n.intValue() in v++ ...; Here, since n is of type T, a type variable whose bound is Object. Since no synthetic cast is added by the compiler, the LetExpr flows into the compiler pipeline, thus causing bad code to be generated since T is erased to Object and Object does not define a method intValue(). The solution to the problem is to force an explicit type conversion to the actual type of T (which is known at compile-time) so that the LetExpr node is generated as follows: let int v = ((Integer)n).intValue() in v++ ...;
2008-02-11

SUGGESTED FIX http://sa.sfbay.sun.com/projects/langtools_data/7/6614974/
2008-02-11

EVALUATION Cast from Object to Integer is missing before pc=46. public void error(); Code: 0: new #2; //class BugReport 3: dup 4: invokespecial #3; //Method "<init>":()V 7: astore_1 8: aload_1 9: iconst_0 10: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 13: putfield #5; //Field n:Ljava/lang/Object; 16: aload_1 17: astore_2 18: aload_2 19: getfield #5; //Field n:Ljava/lang/Object; 22: astore_3 23: aload_2 24: aload_2 25: getfield #5; //Field n:Ljava/lang/Object; 28: checkcast #6; //class java/lang/Integer 31: invokevirtual #7; //Method java/lang/Integer.intValue:()I 34: iconst_1 35: iadd 36: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 39: dup_x1 40: putfield #5; //Field n:Ljava/lang/Object; 43: astore 4 45: aload_3 *** aload_3 loads raw type val.n; *** need checkcast #6 // class java/lang/Integer 46: invokevirtual #7; //Method java/lang/Integer.intValue:()I 49: invokestatic #8; //Method java/lang/Integer.toString:(I)Ljava/lang/String; 52: pop 53: return
2008-01-04