Bug 159973 - [1.5] [compiler] VerifyError due to compiler generating incorrect synthetic methods
Summary: [1.5] [compiler] VerifyError due to compiler generating incorrect synthetic m...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.3   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 3.2.2   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 160254 161442 (view as bug list)
Depends on:
Blocks:
 
Reported: 2006-10-06 03:37 EDT by Bas de Bakker CLA
Modified: 2007-01-16 02:36 EST (History)
6 users (show)

See Also:


Attachments
Proposed fix (1.56 KB, patch)
2006-10-11 15:16 EDT, Olivier Thomann CLA
no flags Details | Diff
Proposed fix (1.35 KB, patch)
2006-10-11 21:47 EDT, Olivier Thomann CLA
no flags Details | Diff
Regression tests (13.43 KB, patch)
2006-10-11 21:48 EDT, Olivier Thomann CLA
no flags Details | Diff
Better patch (1.31 KB, patch)
2006-10-12 03:59 EDT, Philipe Mulet CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Bas de Bakker CLA 2006-10-06 03:37:39 EDT
The test code:

public class EclipseBug {

  private interface ReturnBase {
    // Empty
  }
  
  private interface ReturnDerived extends ReturnBase {
    // Empty
  }
  
  private interface Interface {
    ReturnBase bar();
  }
  
  private static class Implementation {
    public final ReturnDerived bar() {
      return null;
    }
  }
  
  private static class Child extends Implementation implements Interface {
    // Empty
  }
  
  private static class Grandchild extends Child implements Interface {
    // Empty
  }
  
  public static void main(String[] args) {
    new Grandchild();
  }
}

Trying to run this class results in
Exception in thread "main" java.lang.VerifyError: class EclipseBug$Grandchild overrides final method bar.()LEclipseBug$ReturnBase;
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
	at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
	at EclipseBug.main(EclipseBug.java:30)

I expected it to do nothing (which is also what happens when using the Sun javac).

This happens in Eclipse 3.3M1 and 3.3M2. I have not tried it with earlier versions.
Comment 1 Olivier Thomann CLA 2006-10-06 11:17:41 EDT
Bridge methods are added to override a final method leading to the VerifyError.
compliance >= 1.5 is required to compile this code.
Comment 2 Martin Probst CLA 2006-10-09 07:03:55 EDT
I can confirm it happens in 3.2.1, too.
Comment 3 Olivier Thomann CLA 2006-10-11 14:43:13 EDT
The only difference between 3.2.0 and HEAD or 3.2.1 is that the bridge method is final.
I'll check the diff between 3.2.0 and 3.2.1 to find out when this was introduced.
Comment 4 Olivier Thomann CLA 2006-10-11 14:44:55 EDT
In this case javac doesn't create a bridge method at all.
Comment 5 Olivier Thomann CLA 2006-10-11 15:05:06 EDT
The problem seems to come from the fix for bug 147690.
I might have a fix for it that also passes the regression test for 147690, but we should investigate why we do have a bridge method in this case and javac doesn't.
Comment 6 Olivier Thomann CLA 2006-10-11 15:16:54 EDT
Created attachment 51792 [details]
Proposed fix
Comment 7 Martin Probst CLA 2006-10-11 16:13:32 EDT
Please note that this is not for sure a regression bug, ie. I don't know whether it happens in 3.2.0 and Bas doesn't either, as far as I know. 

So to my knowledge this bug might always have been there.
Comment 8 Olivier Thomann CLA 2006-10-11 16:59:52 EDT
From what I tried, it worked fine in 3.2.0, but failed in 3.2.1 due to the fix for bug 147690.
Discussing with Kent, we should have a bridge method on Child, but not on Grandchild, since Child has one.
I'll test a better fix and if it is good, I'll attach it to the PR.
This would definitely be a candidate for 3.2.2.
The previous fix was passing the VerifyError, but I end up with a bridge method for Child and Grandchild. All tests should be done by tomorrow.
Comment 9 Philipe Mulet CLA 2006-10-11 17:51:26 EDT
+1 for 3.2.2.
We have been having the extra bridge method on GrandChild before 3.2.0.
Comment 10 Philipe Mulet CLA 2006-10-11 17:52:46 EDT
If we fix the extra bridge method, it is unclear we need to clear the final flag, other than for matching expectation. We would reject subsequent overrides anyway,
e.g.
public class X {
  private interface ReturnBase {}
  private interface ReturnDerived extends ReturnBase {}
  private interface ReturnLeaf extends ReturnDerived {}
  private interface Interface {
    ReturnBase bar();
  }
  private static class Implementation {
    public final ReturnDerived bar() {
      return null;
    }
  }
  private static class Child extends Implementation implements Interface {}
  private static class Grandchild extends Child implements Interface {
		public ReturnLeaf bar() { 
			return null; 
		}
  }
  public static void main(String[] args) {
    new Grandchild();
  }
}
Comment 11 Philipe Mulet CLA 2006-10-11 17:54:05 EDT
Pls make sure bridge fix is not order dependant:
e.g.
public class X {
  private interface ReturnBase {}
  private interface ReturnDerived extends ReturnBase {}
  private interface Interface {
    ReturnBase bar();
  }
  private static class Implementation {
    public final ReturnDerived bar() {
      return null;
    }
  }
  private static class Grandchild extends Child implements Interface {}
  private static class Child extends Implementation implements Interface {}
  public static void main(String[] args) {
    new Grandchild();
  }
}
Comment 12 Olivier Thomann CLA 2006-10-11 21:47:47 EDT
Created attachment 51822 [details]
Proposed fix

This patch removes the needs to clear the final bit since it generates only one bridge method.
Comment 13 Olivier Thomann CLA 2006-10-11 21:48:26 EDT
Created attachment 51823 [details]
Regression tests

Several regression tests added to cover corner cases.
Comment 14 Philipe Mulet CLA 2006-10-12 03:49:10 EDT
The interface only check tricked me, so I wrote the following test case, which we pass, since another pass is followed for abstract method situations:
we still issue a bridge on Bar.

public class X {
	interface A1 {}
	interface A2 extends A1 {}
	abstract static class AbstractBar {
		abstract A1 bar();
	}
	static class Bar extends AbstractBar {
		@Override  	A2 bar() { return null; }
	}
}

Now the patch should be improved to check for interface first, since this is the less expensive check.
Comment 15 Philipe Mulet CLA 2006-10-12 03:55:04 EDT
BTW, the fix doesn't work with generics.

public class X {
  private interface ReturnBase {}
  private interface ReturnDerived extends ReturnBase {}

  private interface Interface<E> {
    ReturnBase bar();
  }
  private static class Implementation<T> {
    public final ReturnDerived bar() { return null; }
  }
  private static class Child<U> extends Implementation<U> implements Interface<U> {}
  private static class Grandchild<V> extends Child<V> implements Interface<V> {}

  public static void main(String[] args) {
    new Grandchild();
  }
}
Comment 16 Philipe Mulet CLA 2006-10-12 03:58:51 EDT
Also in the proposed patch, the check on concreteMethod.declaringClass is subsumed by the next check on superclass.

Comment 17 Philipe Mulet CLA 2006-10-12 03:59:46 EDT
Created attachment 51836 [details]
Better patch

Also you should check javac behavior for final bit clearance. Though not mandated, might still be a good idea for easing compatibility.
Comment 18 Philipe Mulet CLA 2006-10-12 04:01:31 EDT
Olivier - pls mirror all testcases with generics.

We should issue this fix for the 3.2.1 patch feature. Please talk with Frederic, once all our testing has completed.
Comment 19 Olivier Thomann CLA 2006-10-12 10:04:44 EDT
When javac adds a bridge method, it seems that the final bit is cleared.
Comment 20 Olivier Thomann CLA 2006-10-12 13:52:52 EDT
Released for 3.3M3.
Regression tests added in org.eclipse.jdt.core.tests.compiler.regression.MethodVerifyTest#test102-112
Comment 21 Olivier Thomann CLA 2006-10-12 13:56:55 EDT
Reopen for releasing in 3.2.2
Comment 22 Olivier Thomann CLA 2006-10-12 14:02:24 EDT
Released for 3.2.2.
Same regression tests added.
Comment 23 Olivier Thomann CLA 2006-10-16 11:30:13 EDT
*** Bug 160254 has been marked as a duplicate of this bug. ***
Comment 24 Olivier Thomann CLA 2006-10-23 19:09:22 EDT
*** Bug 161442 has been marked as a duplicate of this bug. ***
Comment 25 David Audel CLA 2006-10-30 07:00:44 EST
Verified for 3.3 M3 using build I20061030-0010
Comment 26 Maxime Daniel CLA 2007-01-16 02:36:21 EST
Verified for 3.2.2 using build M20070112-1200.