JDK-8166203 : NoClassDefFoundError should not be thrown if class is in_error_state at link time
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2016-09-16
  • Updated: 2016-10-21
  • Resolved: 2016-10-21
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 Availability Release.

To download the current JDK release, click here.
JDK 10 JDK 9
10Fixed 9Fixed
Related Reports
Relates :  
Description
For the case where a class has an initialization error, the class is already linked so this code is wrong in link_class_impl:

  // check for error state. This is checking for the wrong state.
  // If initialization_error, then this class *was* linked.
  if (this_k->is_in_error_state()) {
    ResourceMark rm(THREAD);
    THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(),
               this_k->external_name(), false);
  }

There is nothing in the spec that says to throw NCDFE for link time exceptions.  This also prevents linking interfaces that extend interfaces that have had initialization errors, which is also legal in the spec.  In the JLS 12.4.2 step 7, implies that initialization errors in interfaces do not affect other interfaces.   Linking interfaces should not be dependent on initialization state either (there's nothing in the spec about this).

Here's a test program that demonstrates this.

--- begin source ---
class Test {
    static Object someMethod() { throw new RuntimeException("initialization_error"); }
    static boolean out(String s) { System.out.println(s); return true; }

    // K interface with a default method has an initialization error
    interface K {
        static final Object CONST = someMethod(); 
        default int method() { return 2; }
    }

    // Iunlinked is not linked when K gets an initialization error.  Linking Iunlinked should not
    // get NoClassDefFoundError because it does not depend on the initialization state of K for
    // linking.  There's bug now where it does, filed separately.
    interface Iunlinked extends K {
        boolean v = out("Iunlinked");
    }

  static class C implements K {}

  public static void main(java.lang.String[] unused) {
      try {
          C c = new C();
      } catch (ExceptionInInitializerError e) {
          System.out.println("this is expected");
      }
      boolean b = Iunlinked.v;   // should not fail!
  }
}
--- end source ---

I tested the jvm with removing the code above and everything passes, except CDS uses initialization_error state for some purpose that I can't unwind right now.  See linked bug for more.

Suggested fix is to create a state < linked and use this in the CDS code.  You can't use initialization_error.