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.
This commit is contained in:
Ryan Ernst 2024-07-12 14:53:01 -07:00 committed by GitHub
parent c96f801687
commit e4349f8787
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,6 +11,7 @@ package org.elasticsearch.nativeaccess.jna;
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 @@ class JnaPosixCLibrary implements PosixCLibrary {
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);