Describe the bug
JniLibLoader.toRealPath() hand-rolls a symlink-resolution loop:
while (Files.isSymbolicLink(Paths.get(realPath))) {
realPath = Files.readSymbolicLink(Paths.get(realPath)).toString();
}
Files.readSymbolicLink returns the target as stored, which is typically a relative path for versioned native libraries (libfoo.so -> libfoo.so.1 -> libfoo.so.1.2.3). The next iteration feeds that relative target back into Paths.get(realPath), which resolves it against the process working directory — not against the link's own parent. That yields a non-existent path or, worse, a path that happens to exist somewhere unrelated, and System.load(...) then loads the wrong library or fails.
The same loop also has no cycle guard: a symlink cycle (a -> b -> a) makes it spin forever.
Discovered while reviewing the L1 foundation utilities in gluten-core (same area as #12392).
Expected behavior
Resolution should follow each link relative to its own parent, and a cycle should fail fast.
The cleanest path is to delegate to the JDK's Path#toRealPath, which canonicalises the full chain (relative or absolute), normalises ./.., and raises FileSystemLoopException on cycles — no hand-rolled loop and no magic guard counter needed.
Patch and tests are ready; will send a PR.
Describe the bug
JniLibLoader.toRealPath()hand-rolls a symlink-resolution loop:Files.readSymbolicLinkreturns the target as stored, which is typically a relative path for versioned native libraries (libfoo.so -> libfoo.so.1 -> libfoo.so.1.2.3). The next iteration feeds that relative target back intoPaths.get(realPath), which resolves it against the process working directory — not against the link's own parent. That yields a non-existent path or, worse, a path that happens to exist somewhere unrelated, andSystem.load(...)then loads the wrong library or fails.The same loop also has no cycle guard: a symlink cycle (
a -> b -> a) makes it spin forever.Discovered while reviewing the L1 foundation utilities in
gluten-core(same area as #12392).Expected behavior
Resolution should follow each link relative to its own parent, and a cycle should fail fast.
The cleanest path is to delegate to the JDK's
Path#toRealPath, which canonicalises the full chain (relative or absolute), normalises./.., and raisesFileSystemLoopExceptionon cycles — no hand-rolled loop and no magic guard counter needed.Patch and tests are ready; will send a PR.