JDK-8069005 : Hotspot crashes in System.out.println with assert(resolved_method->method_holder()->is_linked()) failed: must be linked
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8u31
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86_64
  • Submitted: 2015-01-14
  • Updated: 2019-07-17
  • Resolved: 2015-05-05
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 9
9 b66Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
I added a println statement to java.security.AccessController as follows:

diff -r 5524b5afe01c src/share/classes/java/security/AccessController.java
--- a/src/share/classes/java/security/AccessController.java	Mon Jan 12 15:08:38 2015 -0800
+++ b/src/share/classes/java/security/AccessController.java	Wed Jan 14 12:43:13 2015 -0500
@@ -823,6 +823,7 @@
             // to return null though, so we construct a real ACC.
             return new AccessControlContext(null, true);
         } else {
+            System.out.println("Stack context isAuth: " + acc.isAuthorized());
             return acc.optimize();
         }
     }

and hotspot crashed with the following log/stack trace (pathname sanitized):

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (.../hotspot/src/share/vm/interpreter/linkResolver.cpp:1184), pid=19086, tid=139969356101376
#  assert(resolved_method->method_holder()->is_linked()) failed: must be linked
#
# JRE version:  (8.0) (build )
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.51-b01-fastdebug mixed mode linux-amd64 compressed oops)
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00007f4d2000b000):  JavaThread "main" [_thread_in_vm, id=19089, stack(0x00007f4d27aff000,0x00007f4d27c00000)]

Stack: [0x00007f4d27aff000,0x00007f4d27c00000],  sp=0x00007f4d27bfd340,  free space=1016k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x103c8f0]  VMError::report_and_die()+0x160
V  [libjvm.so+0x72946b]  report_vm_error(char const*, int, char const*, char const*)+0x7b
V  [libjvm.so+0xbfb6dd]  LinkResolver::runtime_resolve_virtual_method(CallInfo&, methodHandle, KlassHandle, Handle, KlassHandle, bool, Thread*)+0x17d
V  [libjvm.so+0xbfc302]  LinkResolver::resolve_virtual_call(CallInfo&, Handle, KlassHandle, KlassHandle, Symbol*, Symbol*, KlassHandle, bool, bool, Thread*)+0x182
V  [libjvm.so+0xbfca18]  LinkResolver::resolve_invokevirtual(CallInfo&, Handle, constantPoolHandle, int, Thread*)+0x268
V  [libjvm.so+0xbfef53]  LinkResolver::resolve_invoke(CallInfo&, Handle, constantPoolHandle, int, Bytecodes::Code, Thread*)+0x63
V  [libjvm.so+0x9c6cd4]  InterpreterRuntime::resolve_invoke(JavaThread*, Bytecodes::Code)+0x2d4
j  java.util.Arrays.<clinit>()V+2
v  ~StubRoutines::call_stub
V  [libjvm.so+0x9d50c7]  JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*)+0xfb7
V  [libjvm.so+0x9334df]  InstanceKlass::call_class_initializer_impl(instanceKlassHandle, Thread*)+0xdf
V  [libjvm.so+0x933717]  InstanceKlass::call_class_initializer(Thread*)+0x97

etc ... (full trace is in attachment)

Comments
Because of linked bug JDK-8078653 I added code to the assert place to help with diagnosing this problem, ie: philli% java -Xbootclasspath/p:tmp/java.base -version Error occurred during initialization of VM desiredAssertionStatus is called before java/lang/Class is initialized but moving up java.lang.Class initialization gives more help, so this fix will also do this. java -Xbootclasspath/p:tmp/java.base -version Error occurred during initialization of VM java.lang.NullPointerException at java.security.AccessController.getContext(AccessController.java:836) at java.lang.Thread.init(Thread.java:412) at java.lang.Thread.init(Thread.java:349) at java.lang.Thread.<init>(Thread.java:532) I think catching uninitialized classes in linkResolver is still too late but I didn't find a better place to detect this yet. We create instances of java.lang.Class, java.lang.String and java.lang.Throwables well before these classes are linked (and can be linked) during startup.
29-04-2015

Sounds fine Coleen - thanks.
26-04-2015

> I wonder whether there is something the LinkResolver could check that says "I'm trying to throw an exception here!" ?? Honestly, I don't know. It's sort of in the middle of resolution and I don't know how it got this far without j.l.C initialized. The assert is in a place where we really want to assert that the class is initialized because everything later is invalid. Perhaps adding conditionals like !is_init_completed() && the assert condition and doing vm_exit_during_initialization() would work but I think it's less desirable than the exception that the fix produces. Also the linkResolver code has too many special conditionals. That said, it may be that we need to add this sort of logic for a future instance of this sort of error. I would rather move up Class initialization instead at this point, because Class initialization seems like something that should be initialized sooner. I hope this sounds okay to you - thanks for the discussion and also thinking about this problem.
24-04-2015

The reflection classes have empty <clinit> methods so that is okay. I'm somewhat surprised Class.<clinit> isn't trigerring more than it is - I guess creating a T[] only requires T to be loaded not initialized. But I should have seen that from the existing order anyway. So this seems reasonably safe, but I still question the usefulness. I wonder whether there is something the LinkResolver could check that says "I'm trying to throw an exception here!" ??
24-04-2015

David posted the "before" initialization order. Initializing java.lang.Class moves a couple things up but I still think this is safe. 0 Initializing 'java/lang/Object' (0x0000000100000fb0) 1 Initializing 'java/lang/CharSequence'(no method) (0x00000001000015a0) 2 Initializing 'java/lang/String' (0x0000000100001798) 3 Initializing 'java/util/Comparator'(no method) (0x0000000100013650) 4 Initializing 'java/lang/String$CaseInsensitiveComparator'(no method) (0x0000000100013848) 5 Initializing 'java/lang/System' (0x0000000100002790) 6 Initializing 'java/lang/reflect/AnnotatedElement'(no method) (0x0000000100001a08) 7 Initializing 'java/lang/reflect/Type'(no method) (0x0000000100001df8) 8 Initializing 'java/lang/Class' (0x0000000100001ff0) 9 Initializing 'java/lang/ThreadGroup'(no method) (0x0000000100007150) 10 Initializing 'java/lang/Thread' (0x0000000100006c68) 11 Initializing 'java/security/Permission'(no method) (0x00000001000142c0) 12 Initializing 'java/security/BasicPermission'(no method) (0x0000000100014500) 13 Initializing 'java/lang/RuntimePermission'(no method) (0x0000000100014758) 14 Initializing 'java/security/AccessController'(no method) (0x00000001000149b0) 15 Initializing 'java/security/AccessControlContext' (0x0000000100003c10) 16 Initializing 'java/lang/reflect/AccessibleObject' (0x00000001000080b8) I'd like to avoid adding a specific error message in the LinkResolver instead of the assert but it may be necessary for the next instance of this sort of bug.
23-04-2015

It does more than just that: static {}; Code: 0: invokestatic #336 // Method registerNatives:()V 3: iconst_1 4: putstatic #2 // Field useCaches:Z 7: iconst_0 8: anewarray #337 // class java/io/ObjectStreamField 11: putstatic #338 // Field serialPersistentFields:[Ljava/io/ObjectStreamField; 14: iconst_0 15: putstatic #1 // Field initted:Z 18: return Please check the order of class initialization calls before and after to see what other classes now get dragged into earlier initialization. I'm not saying this won't work, but any change to the initialization order is very fragile. Further the core-libs folk will need to approve this as it impacts what might be placed in the static init in the future. And given it still doesn't allow the printing to work it seems an unnecessary risk to me.
02-04-2015

All java/lang/Class static initializer does is registerNatives. It does make sense to move the initialization before Thread. This is a lot better than getting a crash during the initialization of Thread. We initialize a java/lang/String before Thread. We could probably get the same crash if java/lang/String was modified to have a println in it's static initializer, except it doesn't have one.
01-04-2015

Moving up the initialization of java/lang/Class before the initialization of java/lang/Thread gives a better exception message and makes sense to initialize java/lang/Class before Thread. The method that was trying to be called is below which seems like it should be called sooner. {method} - this oop: 0x00007fffd38142e8 - method holder: 'java/lang/Class' - constants: 0x00007fffd3809ee0 constant pool [1343] {0x00007fffd3809ee0} for 'java/lang/Class' - access: 0x1 public - name: 'desiredAssertionStatus' - signature: '()Z' The print function gives a NPE exception instead. I don't know if this is better but it's more helpful and doesn't look like a JVM bug. philli% java -version Error occurred during initialization of VM java.lang.NullPointerException at java.security.AccessController.getContext(AccessController.java:836) at java.lang.Thread.init(Thread.java:412) at java.lang.Thread.init(Thread.java:349) at java.lang.Thread.<init>(Thread.java:532)
01-04-2015

Class itself has a lot of other dependencies that may in turn rely on Thread - hence the NPE. There are some things you just can't do in static initialization of core classes like Thread, Class and a number of others. If the VM hasn't reached a point where an exception can be thrown then it has no option but to abort. Thread is one of the first to be initialized because you have to attach to the VM to execute Java code: 0 Initializing 'java/lang/Object' (0xa19b5260) 1 Initializing 'java/lang/CharSequence'(no method) (0xa19b6b78) 2 Initializing 'java/lang/String' (0xa19bbf28) 3 Initializing 'java/util/Comparator'(no method) (0xa1a50308) 4 Initializing 'java/lang/String$CaseInsensitiveComparator'(no method) (0xa1a507d0) 5 Initializing 'java/lang/System' (0xa19cbfb0) 6 Initializing 'java/lang/ThreadGroup'(no method) (0xa19e2960) 7 Initializing 'java/lang/Thread' (0xa19dfae8) 8 Initializing 'java/security/Permission'(no method) (0xa1a53908) 9 Initializing 'java/security/BasicPermission'(no method) (0xa1a53a68) 10 Initializing 'java/lang/RuntimePermission'(no method) (0xa1a53bc8) 11 Initializing 'java/security/AccessController'(no method) (0xa1a554f0) 12 Initializing 'java/security/AccessControlContext' (0xa19d58f8) 13 Initializing 'java/lang/reflect/AnnotatedElement'(no method) (0xa19be448) 14 Initializing 'java/lang/reflect/Type'(no method) (0xa19bea90) 15 Initializing 'java/lang/Class' (0xa19c4e98) Thread in turn has security code so AccessController has to be initialized too. As you can see Class itself is way down the list.
01-04-2015

Christian: at this stage of initialization it is hard to determine exactly what is happening. The assertion tells us that we eventually tried to use a class that had not yet been linked - the assertion is generic, it doesn't know the current state of the VM. I would not consider trying to improve the error message here a "starter" issue. Sean: not really. When faced with a similar problem I would place my debug code in a conditional based on the invocation count eg: static int calls = 0; if (++calls > <some experimentally determined threshold>) do_debug_stuff(); but if you really need to see what happens in the first few calls I'd cache the state you want to see and then dump that when it is safe.
16-01-2015

Is there any hook I can use to tell if it is in this early initialization stage (without walking up the call stack?). I would like to cache some information for debugging and print it out later.
15-01-2015

ILW HLL = P4 I: High, Assert/possible crash L: Low, Won't happen in end user code W: Low, Don't add code like this in early startup parts of the JDK.
15-01-2015

We could improve the error message here rather than asserting/crashing
15-01-2015

Initialization order is very fragile. By adding the println you have tried to use classes earlier than they normally get loaded and it is not possible at that stage of VM initialization. That is what the assertion failure indicates. It is also too soon to be able to throw Java exceptions. The AccessController is loaded while Thread is being initialized, hence very early in the VM initialization process.
15-01-2015