Skip to content
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

native-image-agent ceased to work as expected with AWT/JNI #9300

Closed
Karm opened this issue Jul 12, 2024 · 4 comments
Closed

native-image-agent ceased to work as expected with AWT/JNI #9300

Karm opened this issue Jul 12, 2024 · 4 comments

Comments

@Karm
Copy link
Contributor

Karm commented Jul 12, 2024

Native agent used to work for determining necessary JNI access configuration, e.g. when it comes to loading headless AWT for transforming images.

Here is a small program that does that:

git clone https://github.com/Karm/dev-null.git
cd dev-null/imageio

🟢 GraalVM CE 22.0.1+8.1

$ export JAVA_HOME=/home/karm/X/JDKs/graalvm-community-openjdk-22.0.1+8.1/;export GRAALVM_HOME=${JAVA_HOME};export PATH=${JAVA_HOME}/bin:${PATH}
$ native-image --version
native-image 22.0.1 2024-04-16
GraalVM Runtime Environment GraalVM CE 22.0.1+8.1 (build 22.0.1+8-jvmci-b01)
Substrate VM GraalVM CE 22.0.1+8.1 (build 22.0.1+8, serial gc)
$ mvn clean package
$ java -Djava.awt.headless=true -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/imageio.jar
$ jar uf target/imageio.jar -C src/main/resources/ META-INF
$ native-image -J-Djava.awt.headless=true --no-fallback -jar target/imageio.jar target/imageio
$ ./target/imageio -Djava.awt.headless=true -Djava.home=/tmp/FAKE_JAVA_HOME/

Works, images get generated:

$ ls mytest*
mytest.bmp  mytest.gif  mytest.jpg  mytest.png  mytest_Resized_Grace_M._Hopper.png  mytest.svg  mytest.tiff  mytest_toC.png  mytest_toG.png  mytest_toL.png  mytest_toP.png  mytest_toS.png  mytest.wbmp

Note that the fake JAVA_HOME is an empty directory structure to satisfy code paths that are trying to look for fonts in what it thinks is a JDK folder...

$ find /tmp/FAKE_JAVA_HOME/
/tmp/FAKE_JAVA_HOME/
/tmp/FAKE_JAVA_HOME/conf
/tmp/FAKE_JAVA_HOME/conf/fonts
/tmp/FAKE_JAVA_HOME/lib

Let's backup the config the old agent created:

$ mv src/main/resources/META-INF/native-image ./native-image.old

Now off to the latest dev build:

$ rm -rf mytest* dependency-reduced-pom.xml target/

🔴 GraalVM CE 24-dev+5.1

$ export JAVA_HOME=/home/karm/X/JDKs/graalvm-community-openjdk-24+5.1;export GRAALVM_HOME=${JAVA_HOME};export PATH=${JAVA_HOME}/bin:${PATH}
$ native-image --version
native-image 24 2025-03-18
GraalVM Runtime Environment GraalVM CE 24-dev+5.1 (build 24+5-jvmci-b01)
Substrate VM GraalVM CE 24-dev+5.1 (build 24+5, serial gc)
$ mvn clean package
$ java -Djava.awt.headless=true -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/imageio.jar
$ jar uf target/imageio.jar -C src/main/resources/ META-INF
$ native-image -J-Djava.awt.headless=true --no-fallback -jar target/imageio.jar target/imageio
$ ./target/imageio -Djava.awt.headless=true -Djava.home=/tmp/FAKE_JAVA_HOME/
Fatal error reported via JNI: Could not allocate library name

That fails. The error here is a weird, unrelated message (I'm gonna patch that reporting in JDK's awt_LoadLibrary.c).
The real reason is that no expected C->Java JNI invocations work.
EDIT: Patched upstream: openjdk/jdk#20169

The reachability-metadata.json 's JNI section is wrong. I will try to debug exactly why.

If I ditch it and use the old one:

$ mv src/main/resources/META-INF/native-image ./native-image.new
$ cp ./native-image.old src/main/resources/META-INF/native-image -R
$ jar uf target/imageio.jar -C src/main/resources/ META-INF

And run the build again:

$ native-image -J-Djava.awt.headless=true --no-fallback -jar target/imageio.jar target/imageio

It works and images get generated:

$ ./target/imageio -Djava.awt.headless=true -Djava.home=/tmp/FAKE_JAVA_HOME/

All in all I'd say something changed in the way the native agent works or how it should be used. I will paste more details and debug further.

Karm added a commit to Karm/jdk that referenced this issue Jul 13, 2024
If there is problem with finding and calling e.g. java/awt/GraphicsEnvironment
in AWTIsHeadless, the env' Exception remains set and it not cleared.
Later, that manifests as:

    Fatal error reported via JNI: Could not allocate library name

Which is misleading. The code path is perhaps rare in normal JDK usage,
but it has been complicating our users' bug reports in the GraalVM/native-image
ecosystem for quite some time.

Instead of failing later with some clear message that indicates that the
user has incorrectly configured JNI, it bails out very soon with a message
that seems as if a jstring could not have been allocated. It sends users
on wild goose chases, e.g.

oracle/graal#9138
oracle/graal#8475
oracle/graal#9300
quarkusio/quarkus#31596
graalvm/mandrel#292
Karm/mandrel-integration-tests#262

This commit fixes the error reporting in the AWTIsHeadless.

Furthermore, when AOT compiled, there is little sense for having a JAVA_HOME,
yet some parts of AWT code look for it to search fonts. In such case, an
empty directory structure is enough to accommodate it, e.g.

/tmp/JAVA_HOME/
/tmp/JAVA_HOME/conf
/tmp/JAVA_HOME/conf/fonts
/tmp/JAVA_HOME/lib

The exception is somewhat cryptic for users again, merely stating:

    Exception in thread "main" java.io.IOException: Problem reading font data.
        at [email protected]/java.awt.Font.createFont0(Font.java:1205)
        at [email protected]/java.awt.Font.createFont(Font.java:1076)
        at imageio.Main.loadFonts(Main.java:139

Adding the cause there makes it clearer, i.e. that JAVA_HOME might be missing:

    Exception in thread "main" java.io.IOException: Problem reading font data.
        at java.desktop@23-internal/java.awt.Font.createFont0(Font.java:1206)
        at java.desktop@23-internal/java.awt.Font.createFont(Font.java:1076)
        at imageio.Main.loadFonts(Main.java:139)
        at imageio.Main.paintRectangles(Main.java:97)
        at imageio.Main.main(Main.java:195)
        at java.base@23-internal/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
    Caused by: java.lang.Error: java.home property not set
        at java.desktop@23-internal/sun.awt.FontConfiguration.findFontConfigFile(FontConfiguration.java:180)
        at java.desktop@23-internal/sun.awt.FontConfiguration.<init>(FontConfiguration.java:97)
@fniephaus
Copy link
Member

Thanks for raising this! We actually noticed this as well, fixes are already in the making (#9292 and #9305).

@vjovanov
Copy link
Member

The fixes have been merged. Can you please verify if it fixes the issue with the next dev build?

@Karm
Copy link
Contributor Author

Karm commented Jul 17, 2024

@vjovanov I can confirm that it works with the HEAD 71e6492, Mandrel dev build mandrel-java24-linux-amd64-24.2.0-dev71e64925a07.tar.gz.

@fniephaus
Copy link
Member

Great, thanks for checking!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants