Thu, 13 Oct 2016 11:57:45 -0400
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) {