Skip to content

Commit

Permalink
Force resolution of fstat64 symbol with JNA (elastic#110807)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rjernst authored Jul 12, 2024
1 parent c96f801 commit e4349f8
Showing 1 changed file with 10 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit e4349f8

Please sign in to comment.