-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
8336382: Fixes error reporting in loading AWT and fonts #20169
base: master
Are you sure you want to change the base?
Conversation
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)
👋 Welcome back Karm! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
Webrevs
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, please update copyright years in the changed files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is nothing in this PR that I would accept. It should be withdrawn.
Hello @prrace TBH, I got somewhat bewildered by your comments on how this PR makes no sense. Then I realized I might have been erroneously treating the If you take a look at the flow of Previous fixSo I made this PR, thinking that for some headless JDK distributions it is O.K. to be entirely missing @@ -62,15 +62,24 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
graphicsEnvClass = (*env)->FindClass(env,
"java/awt/GraphicsEnvironment");
if (graphicsEnvClass == NULL) {
+ // Not finding the class is not necessarily an error.
+ if ((*env)->ExceptionCheck(env)) {
+ (*env)->ExceptionClear(env);
+ }
return JNI_TRUE;
}
headlessFn = (*env)->GetStaticMethodID(env,
graphicsEnvClass, "isHeadless", "()Z");
if (headlessFn == NULL) {
+ // If we can't find the method, we assume headless mode.
+ if ((*env)->ExceptionCheck(env)) {
+ (*env)->ExceptionClear(env);
+ }
return JNI_TRUE;
}
isHeadless = (*env)->CallStaticBooleanMethod(env, graphicsEnvClass,
headlessFn);
+ // If an exception occurred, we assume headless mode.
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env);
return JNI_TRUE; New fixThe new fix I propose treats the missing class or missing method as fatal errors. The crash makes sense, the error message is correct:
It's a little more invasive though: diff --git a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
index 0fc44bfca71..7ef6dab8682 100644
--- a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
+++ b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
@@ -43,6 +43,12 @@
#define VERBOSE_AWT_DEBUG
#endif
+#define CHECK_EXCEPTION_FATAL(env, message) \
+ if ((*env)->ExceptionCheck(env)) { \
+ (*env)->ExceptionClear(env); \
+ (*env)->FatalError(env, message); \
+ }
+
static void *awtHandle = NULL;
typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved);
@@ -61,25 +67,13 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
graphicsEnvClass = (*env)->FindClass(env,
"java/awt/GraphicsEnvironment");
- if (graphicsEnvClass == NULL) {
- // Not finding the class is not necessarily an error.
- if ((*env)->ExceptionCheck(env)) {
- (*env)->ExceptionClear(env);
- }
- return JNI_TRUE;
- }
+ CHECK_EXCEPTION_FATAL(env, "java/awt/GraphicsEnvironment class not found");
headlessFn = (*env)->GetStaticMethodID(env,
graphicsEnvClass, "isHeadless", "()Z");
- if (headlessFn == NULL) {
- // If we can't find the method, we assume headless mode.
- if ((*env)->ExceptionCheck(env)) {
- (*env)->ExceptionClear(env);
- }
- return JNI_TRUE;
- }
+ CHECK_EXCEPTION_FATAL(env, "isHeadless method not found");
isHeadless = (*env)->CallStaticBooleanMethod(env, graphicsEnvClass,
headlessFn);
- // If an exception occurred, we assume headless mode.
+ // If an exception occurred, we assume headless mode and carry on.
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env);
return JNI_TRUE;
@@ -88,12 +82,6 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
return isHeadless;
}
-#define CHECK_EXCEPTION_FATAL(env, message) \
- if ((*env)->ExceptionCheck(env)) { \
- (*env)->ExceptionClear(env); \
- (*env)->FatalError(env, message); \
- }
-
/*
* Pathnames to the various awt toolkits
*/ Thanks for your time. I hope the PR makes more sense now or at least that I managed to get my point across. If you think there is a better way to handle it, tell me and I'll do it. I don't dwell on a particular implementation, I merely want the misleading error gone. Thx |
I think we're all finding it a bit hard to understand what to do. Is the problem that
Please, help us here. |
P.S. There surely is an actual problem here: the error message that is currently output misrepresents the actual cause of the failure. |
ping @prrace |
@Karm There are a few things that have not yet been addressed:
I'd also merge in latest master since x86 tests have since been disabled. That should fix the GHA issue. Thanks! |
… java.homenot set and AWT cannot try to lookup fonts
Hello @jerboaa, The year there is 2024 for both edited files.
Use the title from this PR, please.
Done. |
Font.java and information leakageWould this solution address the concern? Instead of passing on the whole throwable, we just inspect it and if it is this particular one, we pass on the information to the user?
|
I retract this. It's not that inconvenient and I don't want to complicate this PR. |
Done. |
@prrace I added a test that triggers the described issue. Unpatched awt_LoadLibrary.c
Patched awt_LoadLibrary.c
|
Hello @mrserb, could you take a look, please? |
if (graphicsEnvClass == NULL) { | ||
return JNI_TRUE; | ||
} | ||
CHECK_EXCEPTION_FATAL(env, "java/awt/GraphicsEnvironment class not found"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking out any discussion about graal/etc as well as absent of any classes and methods, I agree that the current code is questionable.
But the solution to always print "java/awt/GraphicsEnvironment class not found" does not seems to be correct as well.
One of the problem with this code is an actual conflict between two patches. Both are related to warning caused by pending java exceptions, but implemented differently:
- https://bugs.openjdk.org/browse/JDK-8031001: treated the java exceptions as a fatal errors and fail fast
- https://bugs.openjdk.org/browse/JDK-8130507: ignores the java exceptions and tried to fallback into the headless mode in assumption that it may be fine for the application
Both of that patches only changes the code paths which were reported by "some tools"/checkjni - this is the reason why the next code was not reported and was not patched(which is wrong):
graphicsEnvClass = (*env)->FindClass(env,
"java/awt/GraphicsEnvironment");
if (graphicsEnvClass == NULL) {
return JNI_TRUE;
}
headlessFn = (*env)->GetStaticMethodID(env,
graphicsEnvClass, "isHeadless", "()Z");
if (headlessFn == NULL) {
return JNI_TRUE;
}
If we would like to follow JDK-8031001 approach we should use fatal error here and fail fast, for example if OOM is occurred.
If we would like to follow JDK-8130507 we should clear an exceptions and try to use headless mode.
I guess ignoring an exceptions is not that good and the fix for JDK-8130507 should be rethinking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change the CHECK_EXCEPTION_FATAL macro to something like
#define CHECK_EXCEPTION_FATAL(env, message) \
if ((*env)->ExceptionCheck(env)) { \
(*env)->ExceptionDescribe(env);
(*env)->FatalError(env, message); \
}
In this case the root cause of the bug will always be printed.
And then update the fatal message to some generic text.
Note that the FatalError is used in this code since we always should load the library(libawt_xawt or libawt_headless) or fail fast, otherwise we most probably will get an error later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @mrserb for your time. Let me amend the PR and run tests again.
If there is a problem with finding and calling e.g.
java/awt/GraphicsEnvironment
inAWTIsHeadless
, the env' Exception remains set and it is not cleared. Later, that manifests as:Which is misleading. The code path is perhaps rare in a 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 indicating 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 where it appears
JNU_NewStringPlatform
calls failed, e.g.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:
Adding the cause there makes it clearer, i.e. that JAVA_HOME might be missing:
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/20169/head:pull/20169
$ git checkout pull/20169
Update a local copy of the PR:
$ git checkout pull/20169
$ git pull https://git.openjdk.org/jdk.git pull/20169/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 20169
View PR using the GUI difftool:
$ git pr show -t 20169
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/20169.diff
Webrev
Link to Webrev Comment