8163969: Cyclic interface initialization causes JVM crash

Thu, 13 Oct 2016 11:57:45 -0400

author
coleenp
date
Thu, 13 Oct 2016 11:57:45 -0400
changeset 8640
d2e8a8cd4166
parent 8638
8b37c5a17316
child 8641
40d65a63379b

8163969: Cyclic interface initialization causes JVM crash
Summary: Backport change to correct interface initialization.
Reviewed-by: gtriantafill, sspitsyn, dholmes

src/share/vm/oops/instanceKlass.cpp file | annotate | diff | comparison | revisions
test/runtime/lambda-features/TestInterfaceInit.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/oops/instanceKlass.cpp	Tue Oct 11 14:07:13 2016 -0400
     1.2 +++ b/src/share/vm/oops/instanceKlass.cpp	Thu Oct 13 11:57:45 2016 -0400
     1.3 @@ -616,7 +616,11 @@
     1.4  
     1.5  bool InstanceKlass::link_class_impl(
     1.6      instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) {
     1.7 -  // check for error state
     1.8 +  // check for error state.
     1.9 +  // This is checking for the wrong state.  If the state is initialization_error,
    1.10 +  // then this class *was* linked.  The CDS code does a try_link_class and uses
    1.11 +  // initialization_error to mark classes to not include in the archive during
    1.12 +  // DumpSharedSpaces.  This should be removed when the CDS bug is fixed.
    1.13    if (this_oop->is_in_error_state()) {
    1.14      ResourceMark rm(THREAD);
    1.15      THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(),
    1.16 @@ -801,37 +805,22 @@
    1.17  }
    1.18  
    1.19  // Eagerly initialize superinterfaces that declare default methods (concrete instance: any access)
    1.20 -void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_oop, TRAPS) {
    1.21 -  if (this_oop->has_default_methods()) {
    1.22 -    for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
    1.23 -      Klass* iface = this_oop->local_interfaces()->at(i);
    1.24 -      InstanceKlass* ik = InstanceKlass::cast(iface);
    1.25 -      if (ik->should_be_initialized()) {
    1.26 -        if (ik->has_default_methods()) {
    1.27 -          ik->initialize_super_interfaces(ik, THREAD);
    1.28 -        }
    1.29 -        // Only initialize() interfaces that "declare" concrete methods.
    1.30 -        // has_default_methods drives searching superinterfaces since it
    1.31 -        // means has_default_methods in its superinterface hierarchy
    1.32 -        if (!HAS_PENDING_EXCEPTION && ik->declares_default_methods()) {
    1.33 -          ik->initialize(THREAD);
    1.34 -        }
    1.35 -        if (HAS_PENDING_EXCEPTION) {
    1.36 -          Handle e(THREAD, PENDING_EXCEPTION);
    1.37 -          CLEAR_PENDING_EXCEPTION;
    1.38 -          {
    1.39 -            EXCEPTION_MARK;
    1.40 -            // Locks object, set state, and notify all waiting threads
    1.41 -            this_oop->set_initialization_state_and_notify(
    1.42 -                initialization_error, THREAD);
    1.43 -
    1.44 -            // ignore any exception thrown, superclass initialization error is
    1.45 -            // thrown below
    1.46 -            CLEAR_PENDING_EXCEPTION;
    1.47 -          }
    1.48 -          THROW_OOP(e());
    1.49 -        }
    1.50 -      }
    1.51 +void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_k, TRAPS) {
    1.52 +  assert (this_k->has_default_methods(), "caller should have checked this");
    1.53 +  for (int i = 0; i < this_k->local_interfaces()->length(); ++i) {
    1.54 +    Klass* iface = this_k->local_interfaces()->at(i);
    1.55 +    InstanceKlass* ik = InstanceKlass::cast(iface);
    1.56 +
    1.57 +    // Initialization is depth first search ie. we start with top of the inheritance tree
    1.58 +    // has_default_methods drives searching superinterfaces since it
    1.59 +    // means has_default_methods in its superinterface hierarchy
    1.60 +    if (ik->has_default_methods()) {
    1.61 +      ik->initialize_super_interfaces(ik, CHECK);
    1.62 +    }
    1.63 +
    1.64 +    // Only initialize() interfaces that "declare" concrete methods.
    1.65 +    if (ik->should_be_initialized() && ik->declares_default_methods()) {
    1.66 +      ik->initialize(CHECK);
    1.67      }
    1.68    }
    1.69  }
    1.70 @@ -897,30 +886,36 @@
    1.71    }
    1.72  
    1.73    // Step 7
    1.74 -  Klass* super_klass = this_oop->super();
    1.75 -  if (super_klass != NULL && !this_oop->is_interface() && super_klass->should_be_initialized()) {
    1.76 -    super_klass->initialize(THREAD);
    1.77 -
    1.78 +  // Next, if C is a class rather than an interface, initialize its super class and super
    1.79 +  // interfaces.
    1.80 +  if (!this_oop->is_interface()) {
    1.81 +    Klass* super_klass = this_oop->super();
    1.82 +    if (super_klass != NULL && super_klass->should_be_initialized()) {
    1.83 +      super_klass->initialize(THREAD);
    1.84 +    }
    1.85 +    // If C implements any interfaces that declares a non-abstract, non-static method,
    1.86 +    // the initialization of C triggers initialization of its super interfaces.
    1.87 +    // Only need to recurse if has_default_methods which includes declaring and
    1.88 +    // inheriting default methods
    1.89 +    if (!HAS_PENDING_EXCEPTION && this_oop->has_default_methods()) {
    1.90 +      this_oop->initialize_super_interfaces(this_oop, THREAD);
    1.91 +    }
    1.92 +
    1.93 +    // If any exceptions, complete abruptly, throwing the same exception as above.
    1.94      if (HAS_PENDING_EXCEPTION) {
    1.95        Handle e(THREAD, PENDING_EXCEPTION);
    1.96        CLEAR_PENDING_EXCEPTION;
    1.97        {
    1.98          EXCEPTION_MARK;
    1.99 -        this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads
   1.100 -        CLEAR_PENDING_EXCEPTION;   // ignore any exception thrown, superclass initialization error is thrown below
   1.101 +        // Locks object, set state, and notify all waiting threads
   1.102 +        this_oop->set_initialization_state_and_notify(initialization_error, THREAD);
   1.103 +        CLEAR_PENDING_EXCEPTION;
   1.104        }
   1.105        DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait);
   1.106        THROW_OOP(e());
   1.107      }
   1.108    }
   1.109  
   1.110 -  // Recursively initialize any superinterfaces that declare default methods
   1.111 -  // Only need to recurse if has_default_methods which includes declaring and
   1.112 -  // inheriting default methods
   1.113 -  if (this_oop->has_default_methods()) {
   1.114 -    this_oop->initialize_super_interfaces(this_oop, CHECK);
   1.115 -  }
   1.116 -
   1.117    // Step 8
   1.118    {
   1.119      assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
   1.120 @@ -981,10 +976,15 @@
   1.121  
   1.122  void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) {
   1.123    oop init_lock = this_oop->init_lock();
   1.124 -  ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
   1.125 -  this_oop->set_init_state(state);
   1.126 -  this_oop->fence_and_clear_init_lock();
   1.127 -  ol.notify_all(CHECK);
   1.128 +  if (init_lock != NULL) {
   1.129 +    ObjectLocker ol(init_lock, THREAD);
   1.130 +    this_oop->set_init_state(state);
   1.131 +    this_oop->fence_and_clear_init_lock();
   1.132 +    ol.notify_all(CHECK);
   1.133 +  } else {
   1.134 +    assert(init_lock != NULL, "The initialization state should never be set twice");
   1.135 +    this_oop->set_init_state(state);
   1.136 +  }
   1.137  }
   1.138  
   1.139  // The embedded _implementor field can only record one implementor.
     2.1 --- a/test/runtime/lambda-features/TestInterfaceInit.java	Tue Oct 11 14:07:13 2016 -0400
     2.2 +++ b/test/runtime/lambda-features/TestInterfaceInit.java	Thu Oct 13 11:57:45 2016 -0400
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -25,7 +25,8 @@
    2.11  /*
    2.12   * @test
    2.13   * @bug 8034275
    2.14 - * @summary [JDK 8u40] Test interface initialization: only for interfaces declaring default methods
    2.15 + * @bug 8163969
    2.16 + * @summary [JDK 8u40] Test interface init: only for interfaces declaring default methods, when subclass inits
    2.17   * @run main TestInterfaceInit
    2.18   */
    2.19  import java.util.List;
    2.20 @@ -39,43 +40,59 @@
    2.21     // Declares a default method and initializes
    2.22     interface I {
    2.23         boolean v = TestInterfaceInit.out(I.class);
    2.24 -        default void x() {}
    2.25 +        default void ix() {}
    2.26     }
    2.27  
    2.28     // Declares a default method and initializes
    2.29     interface J extends I {
    2.30         boolean v = TestInterfaceInit.out(J.class);
    2.31 -       default void x() {}
    2.32 +       default void jx() {}
    2.33     }
    2.34 -   // No default method, does not initialize
    2.35 +   // No default method, has an abstract method, does not initialize
    2.36     interface JN extends J {
    2.37         boolean v = TestInterfaceInit.out(JN.class);
    2.38 +       public abstract void jnx();
    2.39     }
    2.40  
    2.41     // Declares a default method and initializes
    2.42     interface K extends I {
    2.43         boolean v = TestInterfaceInit.out(K.class);
    2.44 -        default void x() {}
    2.45 +        default void kx() {}
    2.46     }
    2.47  
    2.48 -   // No default method, does not initialize
    2.49 +   // No default method, has a static method, does not initialize
    2.50     interface KN extends K {
    2.51         boolean v = TestInterfaceInit.out(KN.class);
    2.52 +       static void knx() {}
    2.53     }
    2.54  
    2.55     interface L extends JN, KN {
    2.56         boolean v = TestInterfaceInit.out(L.class);
    2.57 -        default void x() {}
    2.58 +        default void lx() {}
    2.59 +   }
    2.60 +
    2.61 +   static class ChildClass implements JN, KN {
    2.62 +       boolean v = TestInterfaceInit.out(ChildClass.class);
    2.63 +       public void jnx() {}
    2.64     }
    2.65  
    2.66     public static void main(String[] args) {
    2.67         // Trigger initialization
    2.68         boolean v = L.v;
    2.69  
    2.70 -       List<Class<?>> expectedCInitOrder = Arrays.asList(I.class,J.class,K.class,L.class);
    2.71 +       List<Class<?>> expectedCInitOrder = Arrays.asList(L.class);
    2.72         if (!cInitOrder.equals(expectedCInitOrder)) {
    2.73           throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder));
    2.74         }
    2.75 +
    2.76 +       ChildClass myC = new ChildClass();
    2.77 +       boolean w = myC.v;
    2.78 +
    2.79 +       expectedCInitOrder = Arrays.asList(L.class,I.class,J.class,K.class,ChildClass.class);
    2.80 +       if (!cInitOrder.equals(expectedCInitOrder)) {
    2.81 +         throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder));
    2.82 +       }
    2.83 +
    2.84     }
    2.85  
    2.86     static boolean out(Class c) {

mercurial