Skip to content

[Native Image] Unable to use Attach API from native-image client application #11103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 tasks done
dtetreau-Oracle opened this issue Apr 29, 2025 · 3 comments
Open
2 tasks done

Comments

@dtetreau-Oracle
Copy link

dtetreau-Oracle commented Apr 29, 2025

Describe the Issue

I am attempting to use the VirtualMachine Attach API from inside a Java program compiled with GraalVM 24 native-image. I need this API because I am writing a monitoring tool which needs the ability to turn on JMX management features and trigger JFR captures for Java applications which may not have been started with JMX-enabling command line flags.

When run on a normal JVM, the code works normally and I am able to call e.g. VirtualMachine.attach and startLocalManagementAgent, which ultimately lets me open up a JMX connection against the target host. However, when I compile my application to a native image using the currently-latest GraalVM 24 version (graalvm-24-jdk-24.0.1-1.el9.x86_64 and graalvm-24-native-image-24.0.1-1.el9.x86_64) then the VirtualMachine.attach call fails.

java.lang.UnsatisfiedLinkError: Can't load library: attach | java.library.path = [/usr/lib64, /lib64, /lib, /usr/lib]
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibraries.loadLibraryRelative(NativeLibraries.java:141)
    at java.base@24.0.1/java.lang.ClassLoader.loadLibrary(ClassLoader.java:100)
    at java.base@24.0.1/java.lang.Runtime.loadLibrary0(Runtime.java:822)
    at java.base@24.0.1/java.lang.System.loadLibrary(System.java:1663)
    at jdk.attach@24.0.1/sun.tools.attach.VirtualMachineImpl.<clinit>(VirtualMachineImpl.java:404)
    at jdk.attach@24.0.1/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:56)
    at jdk.attach@24.0.1/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:201)

Based on the responses to this Slack thread, apparently this should work since libattach is a JVM-included library, but it is not currently supported.

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

This is the version of Java used to build the native-image:

java version "24.0.1" 2025-04-15
Java(TM) SE Runtime Environment Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmci-b01, mixed mode, sharing)

Operating System and Version

Linux 5.15.0-302.167.6.1.el9uek.x86_64 #2 SMP Thu Nov 21 21:48:29 PST 2024 x86_64 x86_64 x86_64 GNU/Linux

Troubleshooting Confirmation

Run Command

args=(-Djava.security.egd=file:///dev/urandom)
args+=(-Djavax.net.ssl.trustStore=/etc/pki/java/cacerts -Djavax.net.ssl.trustStoreType=jks)
args+=(--add-exports=java.base/sun.security.internal.spec=ALL-UNNAMED,jipher.jce)
args+=(-Djipher.user.dir=var/jipher)
args+=('-Djava.io.tmpdir=var/tmp')
args+=('-Dslf4j.provider=com.oracle.tso.opttools.slf4j.OciLogSlf4jProvider')
args+=('-Doci.log.file.path=var/logs/application.log')
args+=('-Doci.log.level=TRACE')
args+=('-Djdk.serialFilter=*')
args+=('-Djava.library.path=lib')

exec bin/tso-host-agent "${args[@]}"

NOTE the presence of the -Djava.library.path=lib argument. That was from me trying to work around this issue by copying the libattach.so file to a lib directory alongside my binary. However I was never able to get past the UnsatisfiedLinkError no matter what I passed to -Djava.library.path or what permissions I gave to the libattach.so file.

Expected Behavior

My code should be able to successfully attach to the target JVM on the same host and start the local management agent.

Actual Behavior

I am getting an UnsatisfiedLinkError instead, saying that it cannot find the attach library. The attach library is included with the JVM and should be handled automatically by the native image build process.

Steps to Reproduce

  1. Try and use the Attach API from a native image.
  2. See that it fails to attach with an UnsatisfiedLinkError.

Additional Context

No response

Run-Time Log Output and Error Messages

If I don't pass the -Djava.library.path=lib argument:

java.lang.UnsatisfiedLinkError: Can't load library: attach | java.library.path = [/usr/lib64, /lib64, /lib, /usr/lib]
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibraries.loadLibraryRelative(NativeLibraries.java:141)
    at java.base@24.0.1/java.lang.ClassLoader.loadLibrary(ClassLoader.java:100)
    at java.base@24.0.1/java.lang.Runtime.loadLibrary0(Runtime.java:822)
    at java.base@24.0.1/java.lang.System.loadLibrary(System.java:1663)
    at jdk.attach@24.0.1/sun.tools.attach.VirtualMachineImpl.<clinit>(VirtualMachineImpl.java:404)
    at jdk.attach@24.0.1/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:56)
    at jdk.attach@24.0.1/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:201)

If I do pass it:

java.lang.UnsatisfiedLinkError: Can't load library: attach | java.library.path = [lib]
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibraries.loadLibraryRelative(NativeLibraries.java:141)
    at java.base@24.0.1/java.lang.ClassLoader.loadLibrary(ClassLoader.java:100)
    at java.base@24.0.1/java.lang.Runtime.loadLibrary0(Runtime.java:822)
    at java.base@24.0.1/java.lang.System.loadLibrary(System.java:1663)
    at jdk.attach@24.0.1/sun.tools.attach.VirtualMachineImpl.<clinit>(VirtualMachineImpl.java:404)
    at jdk.attach@24.0.1/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:56)
    at jdk.attach@24.0.1/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:201)

In either case the error is the same.

@dtetreau-Oracle
Copy link
Author

Currently my plan to work around this is to package the jcmd tool alongside my native executable, and write code to invoke it as a subprocess and parse its standard output. Of course, jcmd is not a native executable either (otherwise it would run into this same issue), so I'm going to have to include a JVM to run jcmd as well, which defeats the point of having a native build in the first place.

For anyone else who needs to use this workaround, you can at least get a reduced JVM using jlink --add-modules jdk.jcmd --output my-jvm-build --strip-debug --no-man-pages --no-header-files --compress=zip-9, which is better than needing to include the full JVM build.

@olpaw
Copy link
Member

olpaw commented Apr 30, 2025

If someone wants to give it a try ...

This needs something similar to com.oracle.svm.hosted.jdk.JNIRegistrationsJavaZip.
The ReachabilityHandler would need to get registered for sun.tools.attach.AttachProviderImpl#attachVirtualMachine(java.lang.String) and then run:

NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("attach");
NativeLibraries.singleton().addStaticJniLibrary("attach");

@dev-jonghoonpark
Copy link

I'd like to contribute to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: To do
Development

No branches or pull requests

3 participants