JDK-8198826 : -XX:+VerifyStack fails with fatal error: ExceptionMark constructor expects no pending exceptions
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 9,10,11
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-02-28
  • Updated: 2018-03-30
  • Resolved: 2018-03-02
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 11
11 b07Fixed
Related Reports
Relates :  
Description
Running test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java with -XX:+VerifyStack crashes with:

java.lang.OutOfMemoryError 
{0x00000000f80c79b8} - klass: 'java/lang/OutOfMemoryError'
 - ---- fields (total size 5 words):
 - private transient 'backtrace' 'Ljava/lang/Object;' @12  NULL (0)
 - private 'detailMessage' 'Ljava/lang/String;' @16  "Java heap space: failed reallocation of scalar replaced objects"{0x00000000f80d2df8} (f80d2df8)
 - private 'cause' 'Ljava/lang/Throwable;' @20  NULL (0)
 - private 'stackTrace' '[Ljava/lang/StackTraceElement;' @24  NULL (0)
 - private strict 'suppressedExceptions' 'Ljava/util/List;' @28  NULL (0)
 - private transient 'depth' 'I' @32  0

#  Internal Error (/oracle/jdk_hs/open/src/hotspot/share/utilities/exceptions.cpp:484), pid=9967, tid=10020
#  fatal error: ExceptionMark constructor expects no pending exceptions

Stack: [0x00007fa8a006b000,0x00007fa8a016c000],  sp=0x00007fa8a0168040,  free space=1012k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x1525574]  VMError::report_and_die(int, char const*, char const*, __va_list_tag*, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)+0x5b8
V  [libjvm.so+0x1524f1b]  VMError::report_and_die(Thread*, char const*, int, char const*, char const*, __va_list_tag*)+0x65
V  [libjvm.so+0xa60d98]  report_fatal(char const*, int, char const*, ...)+0x108
V  [libjvm.so+0xb8c5a8]  ExceptionMark::ExceptionMark(Thread*&)+0x9a
V  [libjvm.so+0x1259ff6]  OopMapCacheEntry::fill(methodHandle const&, int)+0xe4
V  [libjvm.so+0x125b296]  OopMapCache::compute_one_oop_map(methodHandle const&, int, InterpreterOopMap*)+0xba
V  [libjvm.so+0xa8032a]  Deoptimization::unpack_frames(JavaThread*, int)+0x446
v  blob 0x00007fa8d104f6ac
j  compiler.uncommontrap.TestDeoptOOM.m1(Z)Lcompiler/uncommontrap/TestDeoptOOM;+9
j  compiler.uncommontrap.TestDeoptOOM.main([Ljava/lang/String;)V+24
v  ~StubRoutines::call_stub
V  [libjvm.so+0xda3c6b]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x60b
V  [libjvm.so+0x127cfb1]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x41
V  [libjvm.so+0xda364a]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0xaa
V  [libjvm.so+0x1353a9f]  invoke(InstanceKlass*, methodHandle const&, Handle, bool, objArrayHandle, BasicType, objArrayHandle, bool, Thread*)+0xc29
V  [libjvm.so+0x1353df8]  Reflection::invoke_method(oopDesc*, Handle, objArrayHandle, Thread*)+0x1a0
V  [libjvm.so+0xee8b5e]  JVM_InvokeMethod+0x2a6
C  [libjava.so+0x10392]  Java_jdk_internal_reflect_NativeMethodAccessorImpl_invoke0+0x43
j  jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+0 java.base
j  jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+100 java.base
j  jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6 java.base
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+59 java.base
j  com.sun.javatest.regtest.agent.MainWrapper$MainThread.run()V+172
j  java.lang.Thread.run()V+11 java.base
v  ~StubRoutines::call_stub
V  [libjvm.so+0xda3c6b]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x60b
V  [libjvm.so+0x127cfb1]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x41
V  [libjvm.so+0xda364a]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0xaa
V  [libjvm.so+0xda28a8]  JavaCalls::call_virtual(JavaValue*, Klass*, Symbol*, Symbol*, JavaCallArguments*, Thread*)+0x1a4
V  [libjvm.so+0xda29cf]  JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, Thread*)+0x95
V  [libjvm.so+0xee25df]  thread_entry(JavaThread*, Thread*)+0xa0
V  [libjvm.so+0x148e970]  JavaThread::thread_main_inner()+0x174
V  [libjvm.so+0x148e7da]  JavaThread::run()+0x1a4
V  [libjvm.so+0x1270edc]  thread_native_entry(Thread*)+0x19e


Comments
@Vladimir: Yes, we can do that nice and clean by using a PreserveExceptionMark: http://cr.openjdk.java.net/~thartmann/8198826/webrev.01/ @David: Yes but in this case there is no way we can bail out immediately because we are in the middle of re-building the interpreter state during a deoptimization. I'll follow up with more details in the RFR thread.
01-03-2018

I misunderstood where exactly the exception becomes pending. If it is before the call to unpack_frames then no problem wrt. JRT_LEAF. Proceeding while an exception is pending is quite fragile. You have to look at all of the code to be executed and consider whether it absolutely has to execute - given the exception - and then whether it can execute succesfully, given the pending exception. It raises the risk that anything that follows might take a code-path with an Exceptionmark.
28-02-2018

Can we cache pending exception (as we do in Deoptimization::realloc_objects()) while verifying stack?
28-02-2018

Why not? The exception is not thrown in that method but earlier. And AFAIK it's okay to call leaf methods with a pending exception (in fact, we do that in other code, for example JVMCIRuntime::load_and_clear_exception()). The deoptimization blob (see SharedRuntime::generate_deopt_blob()) first calls into Deoptimization::fetch_unroll_info(): // In order to make fetch_unroll_info work properly with escape // analysis, The method was changed from JRT_LEAF to JRT_BLOCK_ENTRY and // ResetNoHandleMark and HandleMark were removed from it. The actual reallocation // of previously eliminated objects occurs in realloc_objects, which is // called from the method fetch_unroll_info_helper below. If the re-allocation fails in Deoptimization::realloc_objects(), a pre-allocated OOME exception is thrown and propagated onward. From the deopt blob, we then call the leaf method Deoptimization::unpack_frames() with the pending exception.
28-02-2018

ILW = Crash in verification code, with OOM and -XX:+VerifyStack, no workaround = MLH = P4
28-02-2018

Given: JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode)) we should not be able to get a pending OOME as that implies the JRT_LEAF rules have been violated: // JRT_LEAF rules: // A JRT_LEAF method may not interfere with safepointing by // 1) acquiring or blocking on a Mutex or JavaLock - checked // 2) allocating heap memory - checked // 3) executing a VM operation - checked // 4) executing a system call (including malloc) that could block or grab a lock // 5) invoking GC // 6) reaching a safepoint // 7) running too long // Nor may any method it calls.
28-02-2018

If an OutOfMemoryError is thrown during reallocation of scalar replaced objects, stack verification crashes after calling OopMapCache::compute_one_oop_map because that code does not expect pending exceptions. I propose to skip stack verification in this exceptional case: http://cr.openjdk.java.net/~thartmann/8198826/webrev.00/
28-02-2018