JDK-8214975 : No hs-err file if fatal error is raised during dynamic initialization.
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 12
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-12-06
  • Updated: 2019-10-10
  • Resolved: 2019-02-01
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 JDK 13
11.0.6-oracleFixed 13 b07Fixed
Related Reports
Relates :  
Relates :  
Description
A fatal error (e.g. assert), if triggered during dynamic initialization, will plain kill the VM without a trace. (A)

A alternative variant of this error: VM will get caught up in an endless recursion, repeat "[Too many errors, abort]\n" endlessly, quickly growing its RSS until the OOM Killer kills it. (B)

These symptoms are all caused by VMError::report() attempting to write to an fdStream object (VMError::out and VMError::log). These object instances are allocated at global file scope:

1199 fdStream VMError::out(defaultStream::output_fd());
1200 fdStream VMError::log; // error log used by VMError::report_and_die()

They are non-trivial (have vtables) and need to be initialized themselves before being used. If the assert happens before they are initialized, the vtables will not yet have been set up, and once we attempt to call out::write() or log::write(), in an context where we only have an outputStream* ptr (e.g. VMError::report()), we crash.

Depending on which one of VMError::log and VMError::out are still uninitialized, we end up in (A) or (B). In both cases, the secondary signal handler (crash_handler()) will catch the signal, re-try error reporting and crash again. This is an endless cycle. We do have recursion detection in place to stop this cycle:

1388       if (recursive_error_count++ > 30) {
1389        out.print_raw_cr("[Too many errors, abort]");
1390        os::die();
1391      }

but this again uses methods of outputStream to write the "Too many errors" text, which will crash again before ever reaching os::die().






Comments
Fix Request: Would like to fix this in 11 because it is a rare but annoying bug preventing us from getting hs-err reports. In short, C++ objects are used to wrap the log file handles. They are global objects and rely on dynamic initialization. Nature of fix: Fix switches the global C++ objects against simple int variables which do not need dynamic initialization. Low risk because: Fix is simple. Testing done: Nightly SAP tests run thru. Fix does not apply cleanly. RFR: https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2019-September/001862.html Full patch: http://cr.openjdk.java.net/~stuefe/webrevs/backports/8214975-No-hs-err-file-if-fatal-error-is-raised-during-dynamic-initialization-full.patch
18-09-2019

@David (btw user tagging seems only to work for Oracle folks?): You are of course right. Unfortunately, this is such a pervasive pattern that it keeps creeping in. In this case, it was a temporary change I made myself to test something, but which resulted in hanging builds and my machine running out of swap since the CDS dump process crashed in the pattern described above. Error reporting should just be able to handle these situations.
07-12-2018

If you have a quick and simple fix that is fine, but generally there is always a risk of trying to do something too soon during VM initialization. This is why I have tried to push back on things getting initialized (non-trivially) at the C++ static initialization level.
07-12-2018