-
Notifications
You must be signed in to change notification settings - Fork 659
Description
Summary
On Alpine Linux (musl), sqlite-jdbc 3.48.0.0 incorrectly detects the platform as glibc when /proc/self/map_files exists but does not contain any entries referencing musl.
As a result, the driver loads the Linux/x86_64 (glibc) native library instead of Linux-Musl/x86_64, causing runtime crashes due to missing glibc symbols (e.g. __isnan).
This happens even though:
The system is Alpine (musl libc)
ldd --version reports musl
/proc/self/maps clearly shows musl loader
The jar contains the correct Linux-Musl/x86_64 native library
Environment
sqlite-jdbc: 3.48.0.0
OS: Alpine Linux
libc: musl 1.1.24
Kernel: (two different Kubernetes nodes, behavior differs)
Java: OpenJDK 8 (running via javaagent in target JVM)
Container runtime: Kubernetes (multi-node cluster)
Observed Behavior
On one node:
OSInfo.isMusl() -> falseOSInfo.getNativeLibFolderPathForCurrentOS() -> Linux/x86_64
On another node:
OSInfo.isMusl() -> trueOSInfo.getNativeLibFolderPathForCurrentOS() -> Linux-Musl/x86_64
Both nodes:
Same container image
Same jar
Same musl version
Same /lib/ld-musl-x86_64.so.1
Root Cause Analysis
Current implementation (3.48.0.0):
java
public static boolean isMusl() { Path mapFilesDir = Paths.get("/proc/self/map_files"); try (Stream dirStream = Files.list(mapFilesDir)) { return dirStream .map(path -> { try { return path.toRealPath().toString(); } catch (IOException e) { return ""; } }) .anyMatch(s -> s.toLowerCase().contains("musl")); } catch (Exception ignored) { return isAlpineLinux(); }}
Problem
If:
/proc/self/map_files exists
But its entries do not resolve to paths containing "musl"
Then:
Files.list() succeeds
.anyMatch("musl") returns false
No exception is thrown
isAlpineLinux() is never called
isMusl() incorrectly returns false
This causes the driver to load:
Linux/x86_64/libsqlitejdbc.so
instead of:
Linux-Musl/x86_64/libsqlitejdbc.so
On musl systems, this leads to:
Error relocating ... libsqlitejdbc.so: __isnan: symbol not found
And later crashes in JNI calls (e.g. NativeDB.bind_double).
Why This Happens Only On Some Nodes
On some kernels:
/proc/self/map_files
Exists but contains only anonymous mappings
Does not expose musl paths
On other nodes:
/proc/self/map_files is empty or inaccessible
Files.list() throws
Fallback to isAlpineLinux() works correctly
Thus behavior depends on kernel and container runtime, not the image.
Suggested Fix
The current logic treats:
"map_files exists but no musl found"
as equivalent to:
"not musl"
This is unsafe.
Recommended change:
If:
/proc/self/map_files exists
But no entry contains "musl"
Then fallback to isAlpineLinux() instead of returning false.
Example:
java
boolean found = dirStream .map(...) .anyMatch(...);if (!found) { return isAlpineLinux();}return true;
Alternatively:
Use /proc/self/maps instead
Or check for existence of /lib/libc.musl-*.so*
Or rely more strongly on isAlpineLinux()
Impact
This issue causes:
Silent loading of wrong native library
JNI crashes
Difficult-to-debug production failures
Behavior differences across Kubernetes nodes with identical images
Workaround
Set JVM property to force musl native loading:
-Dorg.sqlite.lib.path=/path/to/Linux-Musl/x86_64
Conclusion
OSInfo.isMusl() should not rely solely on /proc/self/map_files presence and contents, as behavior varies across kernels and container environments.
This leads to incorrect platform detection and loading of incompatible native libraries.
/ # ls /proc/self/map_files
55a9c7a25000-55a9c7a31000 55a9c7acd000-55a9c7aee000 55a9c7af3000-55a9c7af4000 7faa71e15000-7faa71e5c000 7faa71e91000- 7faa71e92000
55a9c7a31000-55a9c7acd000 55a9c7aef000-55a9c7af3000 7faa71e00000-7faa71e15000 7faa71e5c000-7faa71e90000 7faa71e92000-7faa71e93000
/ #