JDK-8205965 : SIGSEGV on write to NativeCallStack::EMPTY_STACK
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 9,10,11
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2018-06-28
  • Updated: 2019-09-19
  • Resolved: 2019-01-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 11 JDK 12 JDK 8
11Fixed 12Fixed 8u202Fixed
Related Reports
Relates :  
Relates :  
NativeCallStack::EMPTY_STACK is declared const

const NativeCallStack NativeCallStack::EMPTY_STACK(0, false);

But it's written to here:

  // Construct NativeCallStack::EMPTY_STACK. It may get constructed twice,
  // but it is benign, the results are the same.
  ::new ((void*)&NativeCallStack::EMPTY_STACK) NativeCallStack(0, false);

Writing to a const global is catch-on-fire and it appears that when recent clangs (>= clang-6.0) compile this,  EMPTY_STACK is placed in read-only storage, resulting in SIGSEGV.
The fix is under review: http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2018-June/028959.html I am not sure EMPTY_STACK has to be all zeros, but constexpr probably will do.

Who knew that initializing a C++ global is the most difficult engineering task in the universe? """"static initialization order fiasco""" has its own SIOF acronym. The current code is asking for a SEGV and simply removing the const is the simplest way to stop it. Please either accept this or work towards a more principled solution that only involves a single write to the global. Apparently C++17 has inline static variables but we obviously can't use them yet. EMPTY_STACK is all zero bits in practice - you'd think we could constexpr define it.

Colleague Arthur Eubanks writes """After compiling with google3 clang in release mode, I looked at the symbols before and after removing the const. It's in the read-only data section with the const (thus the crash) and in the BSS data section without the const.""" It seems plausible that after so many decades of optimizer development the compiler could deduce that the constructor NativeCallStack::EMPTY_STACK(0, false) creates a compile-time constant - _hash_value is just 0, and _stack is an array of 4 NULLs.

I am a bit surprised that how can it be placed in read-only storage. Even it is const static object, linker still needs to invoke its constructor at some point, which can overwrite the memory.

Verified that the obvious patch fixes the SIGSEGV (but of course we'd like to keep the const) diff --git a/src/hotspot/share/utilities/nativeCallStack.cpp b/src/hotspot/share/utilities/nativeCallStack.cpp --- a/src/hotspot/share/utilities/nativeCallStack.cpp +++ b/src/hotspot/share/utilities/nativeCallStack.cpp @@ -29,5 +29,5 @@ #include "utilities/nativeCallStack.hpp" -const NativeCallStack NativeCallStack::EMPTY_STACK(0, false); +NativeCallStack NativeCallStack::EMPTY_STACK(0, false); NativeCallStack::NativeCallStack(int toSkip, bool fillStack) : diff --git a/src/hotspot/share/utilities/nativeCallStack.hpp b/src/hotspot/share/utilities/nativeCallStack.hpp --- a/src/hotspot/share/utilities/nativeCallStack.hpp +++ b/src/hotspot/share/utilities/nativeCallStack.hpp @@ -54,5 +54,5 @@ class NativeCallStack : public StackObj { public: - static const NativeCallStack EMPTY_STACK; + static NativeCallStack EMPTY_STACK; private:

hg blame points to Zhengyu changeset: 26144:35e11b657728 25956:99be217ac88d user: zgu date: 2014-08-19 08:34 -0400 8055007: NMT2: emptyStack missing in minimal build Summary: Refactored emptyStack to a static member of NativeCallStack, which is accessible in minimal build. Reviewed-by: coleenp, dholmes