highlight.js

Wednesday, August 11, 2021

JNI Symbol Conflicts in Mac OS

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.

No comments:

Post a Comment

Cue Club 2 on Apple Silicon

It's been quite a long time for me not to play a decent snooker game since I replaced my Windows laptop with an Apple Silicon one. To be...