Background
When I was adding Mac OS support to my open source project
Javet, I found a weird behavior caused by JNI symbol conflicts which resulted in JVM 8 core-dump.
Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java. It's embedding behavior relies on 2 JNI libraries one for Node.js and one for V8. Both of them are loaded by dedicated classloader and share the same API and symbols, except that the Node.js one exposes more Node.js flavored symbols.
In Javet unit test, it loads both Node.js and V8 libraries and performs complicated test. The test goes well in Linux and Windows, but core-dumps in Mac OS.
Analysis
The dump file shows the call stack crosses the library boundary.
...node...dylib
...node...dylib
...node...dylib <== Something wrong happens here.
...v8...dylib
...v8...dylib
...v8...dylib
It seems JVM in Mac OS registers global symbols in the same memory space, so that the V8 library calls into Node.js library. Obviously, that for sure leads to core-dump.
Failed Attempts
- I tried various distributions of JDK 8. None of them worked. It seems to be the Mac OS' behavior.
- I tried to adjust the CMakeLists.txt. All my attempts failed.
Fix
I kept reviewing the call stack and realized the issue might be gone if these symbols were not global symbols.
So I created jni/exported_symbols_list.txt with the following content.
_JNI_OnLoad
_JNI_OnUnload
_Java_com_caoccao_javet_*
_napi_*
Then, I updated CMakeLists.txt with the following content.
target_link_libraries(Javet PUBLIC -exported_symbols_list ${CMAKE_SOURCE_DIR}/jni/exported_symbols_list.txt)
And, it works, no more core-dump with all test cases pass.