From e4349f87873fd18baaf819f8b0cb380ebc4feade Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 12 Jul 2024 14:53:01 -0700 Subject: [PATCH] Force resolution of fstat64 symbol with JNA (#110807) When JNA loads libraries it creates a proxy object for the library. Unfortunately it doesn't actually inspect any of the methods, those get bound lazily at runtime when the method is called through the proxy. For fstat64 we need to know at load time whether the symbol exists, so that we can fallback to an alternate function if it doesn't. This commit looks up the NativeLibrary object from JNA for libc and checks if fstat64 exists during load time. --- .../nativeaccess/jna/JnaPosixCLibrary.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/native/jna/src/main/java/org/elasticsearch/nativeaccess/jna/JnaPosixCLibrary.java b/libs/native/jna/src/main/java/org/elasticsearch/nativeaccess/jna/JnaPosixCLibrary.java index ea5bc4c9e3546..c1148ac96aaa4 100644 --- a/libs/native/jna/src/main/java/org/elasticsearch/nativeaccess/jna/JnaPosixCLibrary.java +++ b/libs/native/jna/src/main/java/org/elasticsearch/nativeaccess/jna/JnaPosixCLibrary.java @@ -11,6 +11,7 @@ import com.sun.jna.Library; import com.sun.jna.Memory; import com.sun.jna.Native; +import com.sun.jna.NativeLibrary; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.Structure; @@ -143,9 +144,17 @@ private interface FXStatFunction extends Library { this.functions = Native.load("c", NativeFunctions.class); FStat64Function fstat64; try { + // JNA lazily finds symbols, so even though we try to bind two different functions below, if fstat64 + // isn't found, we won't know until runtime when calling the function. To force resolution of the + // symbol we get a function object directly from the native library. We don't use it, we just want to + // see if it will throw UnsatisfiedLinkError + NativeLibrary.getInstance("c").getFunction("fstat64"); fstat64 = Native.load("c", FStat64Function.class); } catch (UnsatisfiedLinkError e) { - // TODO: explain + // fstat has a long history in linux from the 32-bit architecture days. On some modern linux systems, + // fstat64 doesn't exist as a symbol in glibc. Instead, the compiler replaces fstat64 calls with + // the internal __fxstat method. Here we fall back to __fxstat, and staticall bind the special + // "version" argument so that the call site looks the same as that of fstat64 var fxstat = Native.load("c", FXStatFunction.class); int version = System.getProperty("os.arch").equals("aarch64") ? 0 : 1; fstat64 = (fd, stat) -> fxstat.__fxstat(version, fd, stat);