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);