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

8323664: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java still fails with JNI warning on some Windows configurations #17404

Closed
wants to merge 7 commits into from

Conversation

RealCLanger
Copy link
Contributor

@RealCLanger RealCLanger commented Jan 12, 2024

This picks up fixing the issue of JDK-8276809 again. A fix had been integrated with #17224 but @prrace had concerns and so it was backed out.

I have now spent quite some thoughts into the problem and end up with the initial commit of #6306 as the most elegant and least intrusive solution.

Why is this?

The JNI warning we observe in the test is:
[WARNING in native method: JNI call made without checking exceptions when required to from CallStaticVoidMethodV at sun.awt.Win32GraphicsEnvironment.initDisplay(java.desktop@22.0.1-internal/Native Method) at sun.awt.Win32GraphicsEnvironment.initDisplayWrapper(java.desktop@22.0.1-internal/Win32GraphicsEnvironment.java:95) at sun.awt.Win32GraphicsEnvironment.<clinit>(java.desktop@22.0.1-internal/Win32GraphicsEnvironment.java:63) ... at FreeTypeScalerJNICheck.runTest(FreeTypeScalerJNICheck.java:53) at FreeTypeScalerJNICheck.main(FreeTypeScalerJNICheck.java:44)

This happens because obviously the test FreeTypeScalerJNICheck runs with -Xcheck:jni and in the scenario where we're observing the warning, a missing exception check for the JNI call to sun.awt.Win32GraphicsEnvironment::dwmCompositionChanged at awt_Win32GraphicsEnv.cpp#L129

is airing up. Omitting the exception check would not be a problem if it could be guaranteed that after this call no other JNI->Java call was being made. But seemingly in this very particular configuration on some of our Windows servers, there must be JNI->Java calls that follow the call to sun.awt.Win32GraphicsEnvironment::dwmCompositionChanged, likely from the subsequent call to initScreens in sun.awt.Win32GraphicsEnvironment::initDisplay.
Java_sun_awt_Win32GraphicsEnvironment_initDisplay(JNIEnv *env,
Maybe the usual control flow would call the wrapping native method DWMIsCompositionEnabled() from somewhere else initially such that the initialization of Win32GraphicsEnvironment would not go through initScreens or similar.

In any case, I think triggering the invocation of JNI's ExceptionCheck by passing a non NULL value as second argument to JNU_CallStaticMethodByName

JNU_CallStaticMethodByName(JNIEnv *env,
is the correct thing to do to get rid of the -Xcheck:jni warning. Note that we don't clear the exception by this. So, should there really be an unchecked exception thrown (unlikely for this call of a simple getter method, but who knows), it would still bubble up to the calling Java code.

@prrace please have a second look.

Also cc @schmelter-sap @MBaesken


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8323664: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java still fails with JNI warning on some Windows configurations (Bug - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/17404/head:pull/17404
$ git checkout pull/17404

Update a local copy of the PR:
$ git checkout pull/17404
$ git pull https://git.openjdk.org/jdk.git pull/17404/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 17404

View PR using the GUI difftool:
$ git pr show -t 17404

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/17404.diff

Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Jan 12, 2024

👋 Welcome back clanger! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk openjdk bot changed the title JDK-8323664 8323664: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java still fails with JNI warning on some Windows configurations Jan 12, 2024
@openjdk
Copy link

openjdk bot commented Jan 12, 2024

@RealCLanger Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information.

@openjdk openjdk bot added the rfr Pull request is ready for review label Jan 12, 2024
@openjdk
Copy link

openjdk bot commented Jan 12, 2024

@RealCLanger The following label will be automatically applied to this pull request:

  • client

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the client client-libs-dev@openjdk.org label Jan 12, 2024
@mlbridge
Copy link

mlbridge bot commented Jan 12, 2024

Webrevs

@prrace
Copy link
Contributor

prrace commented Jan 16, 2024

Maybe the usual control flow would call the wrapping native method DWMIsCompositionEnabled() from somewhere else initially such that the initialization of Win32GraphicsEnvironment would not go through initScreens or similar.

I have not worked out how this can actually happen.
I've built JDK in fast-debug mode and added java.awt.headless=true and added a bunch of printfs to be sure the code is going where I think it is but I can't make this test fail.

I am running my current tests locally on Windows 11, but our CI testing does run this on Windows Server (various versions, 2016, 2019 and 2022)

The only way I can make this fail is to ACTUALLY add a 2nd JNI call in there - I was beginning to wonder if somehow we were missing the WARNING, but in fact that is working.

So your code path is different but what is the exact reason ? That is what we should understand. Maybe it will
be 'ho hum, now I see' or maybe it will point to something we need to address.

@RealCLanger
Copy link
Contributor Author

The test is only failing on a few boxes in our CI infrastructure. And also only in the setup of the nightly tests, not if one would connect to the box and run the test there standalone. But I'll try to run the tests with some more instrumentation to get a better understanding. Stay tuned...

@prrace
Copy link
Contributor

prrace commented Jan 16, 2024

Note that because the test is looking for the string WARNING, it captures all the output of the running VM into a log file, and jtreg will leave that log file there. So you should be able to add instrumentation (ie printf's) into the JDK itself to help understand the internal code flow, and let the test run in that CI environment and capture everything for your later inspection

@RealCLanger
Copy link
Contributor Author

RealCLanger commented Jan 24, 2024

OK, finally it's understood what's happening. Here's the story:

We basically run into the assertion reported in JDK-8185862. It causes the JNI warning through a CallStaticBooleanMethod in its depths. In detail: Via initScreens, called by initDisplay, we call Devices::UpdateInstance that triggers AwtWin32GraphicsDevice::Initialize and here we run into the assertion. The assertion is fired by this VERIFY. In Windows we have an assertion callback installed and it calls Java in isHeadless() which brings up the assertion.

So, how to continue? I think the assertion itself should be addressed through JDK-8185862. We could maybe make the assert callback more robust by checking for a pending exception before calling the isHeadless function. But I think the currently proposed exception check on calling dwmCompositionChanged is also a viable solution. Or we could remove the dwmCompositionChanged call altogether and set the isDWMCompositionEnabled field through JNI's setField function directly. Furthermore, the test FreeTypeScalerJNICheck could also check for "Assertion" in its output, in addition to "Warning". Then it would bail out on both, JNI Warnings and AWT assertions.

WDYT?

@prrace
Copy link
Contributor

prrace commented Jan 24, 2024

by checking for a pending exception before [calling the isHeadless function]

I think that is an acceptable solution for this case.
The isHeadless() code has no guaranteed context as to how it got here and there maybe other places where
we'd have to patch and clearly the call needs to be made even if there's a pending exception, so I would do that.

The broader problem is the reason we get here in this situation in the first place.
It is the combination of (1) the debug build having asserts, (2) a "headless" env where calls fail that trigger the asserts
We really need to fix (2) so that headless doesn't get here.

In the absence of (2) it is likely that testing AWT on debug builds + headless will hit more problems.

@openjdk
Copy link

openjdk bot commented Jan 26, 2024

@RealCLanger This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8323664: java/awt/font/JNICheck/FreeTypeScalerJNICheck.java still fails with JNI warning on some Windows configurations

Reviewed-by: prr, mbaesken, aivanov

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 192 new commits pushed to the master branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Jan 26, 2024
@RealCLanger
Copy link
Contributor Author

Thanks for the review. For some reason, however, I still saw the jni warning in our env with the patch applied. Still looking into it to understand what I'm missing...

@RealCLanger
Copy link
Contributor Author

Thanks for the review. For some reason, however, I still saw the jni warning in our env with the patch applied. Still looking into it to understand what I'm missing...

OK, got it. The exception check needs to be before the call to FindClass. Now the patch is correct and does what it is supposed to do.

@aivanov-jdk
Copy link
Member

Now that I re-read the problem statement and the exception handling JNI, the fix doesn't look correct to me.

What does the warning say?

WARNING in native method: JNI call made without checking exceptions when required to from CallStaticVoidMethodV at sun.awt.Win32GraphicsEnvironment.initDisplay

To me, it means that Win32GraphicsEnvironment.initDisplay is the problem. You found that DWMIsCompositionEnabled calls a static method via JNU_CallStaticMethodByName.

As far as I can see, it's the last statement of the DWMIsCompositionEnabled function.

Then Java_sun_awt_Win32GraphicsEnvironment_initDisplay calls initScreens which, seemingly, can call other JNI methods.

Wouldn't it be better to check if an exception occurred after DWMIsCompositionEnabled and bail out if it did?

    SetProcessDPIAwareProperty();

    DWMIsCompositionEnabled();
    if (env->ExceptionCheck()) {
        return;
    }

    initScreens(env);

Comment on lines +156 to +158
// be on the safe side and avoid JNI warnings by calling ExceptionCheck
// an accumulated exception is not cleared
env->ExceptionCheck();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this doesn't actually do anything but avoids JNI warnings, does it?

AwtDebugSupport::AssertCallback can be called at any time, hence calling JNI functions here is unsafe. Adding env->ExceptionCheck() doesn't change anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. However, it's "only" in the assertion callback that only exists in debug VMs. And an original exception isn't lost.

Copy link
Contributor

@prrace prrace Feb 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps what we should do here is
if (ExceptionCheck) {
ExceptionDescribe
ExceptionClear
}
So someone can "see" [yes, this means it isn't propagated but we've printed it and we have the assert coming up anyway] the text of the original exception, and the debugging code is safe to make the calls it wants.

The alternatives are that the debugging code in the case of ExceptionCheck==TRUE just do what it takes to silence the JNI warnings , assuming that TRUE is never not a possibility, so no real problem, but I don't know see how we can be sure about that for ALL callers of this assert code. (BTW I wonder if the reason the current code didn't do as expected is because ExceptionCheck isn't doing what we expect, but I don't see how), or alternative number 2 is that the debug code simply bails in the face of a pending exception, ie
if (ExceptionCheck) {
return;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see, the real problem is that DWMIsCompositionEnabled calls a Java method and does not check if an exception occurred. It should do it according to the JNI specification.

I can assume initScreens(env) does not call JNI methods, therefore no JNI warning is produced in the regular code flow where no assertions fail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming that TRUE is never not a possibility, so no real problem, but I don't know see how we can be sure about that for ALL callers of this assert code.

We can never be sure about it, even though I tend to believe exceptions are rare.

Essentially, any upcall into Java followed by an assertion will lead to this JNI warning because the assertion handler also upcalls into Java.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said before, the new code just quiesces JNI warnings. It is anyway only used in debug builds. And in the case one sees a "real" exception before entering the assertion handler, this exception will be on the stack when returning to Java and cause the trouble it should then cause. I guess in that case an incorrect tracing of the assertion is no problem. And, after all, the current behavior is not changed.

I would rather like to pull your attention to a "real fix": Please have a look at #17614 (JDK-8185862). It would be good if that can be reviewed and integrated since it will fix a few errors that we see on Windows testing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll take a look at that soon. Remember there are two issues behind all of this
(1) We don't have a real headless build for windows and this can cause failures of windows APIs and Java exceptions
(2) debug builds use asserts on failures of windows APIs

(2) is partially addressed here
(1) is partially addressed in the other fix. I can't be sure its completely addressed

Copy link
Member

@aivanov-jdk aivanov-jdk Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it a bit more…

Since Java_sun_awt_Win32GraphicsEnvironment_initDisplay does not call other JNI functions after DWMIsCompositionEnabled, it is reasonable to leave a possible raised exception unhandled — it will handled by JVM after initDisplay returns.

Perhaps, it's better to handle the exception inside the assertion handler:

if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
}

Or maybe not, if ExceptionCheck() is enough to silence the warning and the raised exception is still thrown after the control is returned to JVM.

@RealCLanger
Copy link
Contributor Author

Now that I re-read the problem statement and the exception handling JNI, the fix doesn't look correct to me.

What does the warning say?

WARNING in native method: JNI call made without checking exceptions when required to from CallStaticVoidMethodV at sun.awt.Win32GraphicsEnvironment.initDisplay

To me, it means that Win32GraphicsEnvironment.initDisplay is the problem. You found that DWMIsCompositionEnabled calls a static method via JNU_CallStaticMethodByName.

As far as I can see, it's the last statement of the DWMIsCompositionEnabled function.

Then Java_sun_awt_Win32GraphicsEnvironment_initDisplay calls initScreens which, seemingly, can call other JNI methods.

Well, yes - however the initScreens only calls other JNI methods through the assert callback of debug builds, so not a general thing. The initial proposal for a fix was to add an exception check right to the call of JNU_CallStaticMethodByName(...,"dwmCompositionChanged",...) but was dismissed by @prrace

I think the current proposal makes the assertion callback more resilient to JNI warnings in general, so I guess it's not bad.

@RealCLanger
Copy link
Contributor Author

I will integrate this in the next days unless somebody explicitly vetoes (given that the PR shows reviews from 3 persons)

@prrace
Copy link
Contributor

prrace commented Feb 11, 2024

I will integrate this in the next days unless somebody explicitly vetoes (given that the PR shows reviews from 3 persons)

I guess that would be OK, but we may revisit this to do one of the things I outlined above.

@RealCLanger
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented Feb 15, 2024

Going to push as commit 99c9ae1.
Since your change was applied there have been 237 commits pushed to the master branch:

  • 0fdfdf7: 8325983: Build failure after JDK-8324580
  • 3b1062d: 8322239: [macos] a11y : java.lang.NullPointerException is thrown when focus is moved on the JTabbedPane
  • 5a988a5: 8322750: Test "api/java_awt/interactive/SystemTrayTests.html" failed because A blue ball icon is added outside of the system tray
  • a231706: 8324580: SIGFPE on THP initialization on kernels < 4.10
  • 2564f0f: 8325906: Problemlist vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id1 until JDK-8320865 is fixed
  • 9a1b843: 8324584: Optimize Symbol and char* handling in ClassLoader
  • a0e5e16: 8325162: Remove duplicate GCMParameters class
  • 0d51b76: 8325877: Split up NativeCompilation.gmk
  • 2b1a840: 8325860: Serial: Move Generation.java to serial folder
  • b718ae3: 8325882: Serial: Move is_maximal_no_gc to TenuredGeneration
  • ... and 227 more: https://git.openjdk.org/jdk/compare/65d6bc1d4c1054e82ace2355d6802e0a7ba24a7f...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Feb 15, 2024
@openjdk openjdk bot closed this Feb 15, 2024
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Feb 15, 2024
@openjdk
Copy link

openjdk bot commented Feb 15, 2024

@RealCLanger Pushed as commit 99c9ae1.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@RealCLanger RealCLanger deleted the JDK-8323664 branch February 15, 2024 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client client-libs-dev@openjdk.org integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

4 participants