-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8282862: AwtWindow::SetIconData leaks old icon handles if an exception is detected #22932
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
Conversation
|
👋 Welcome back rmahajan! A progress list of the required criteria for merging this PR into |
|
@rajamah 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: 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 298 new commits pushed to the
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. As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@honkar-jdk, @aivanov-jdk, @azvegint, @dmarkov20, @prrace) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
Webrevs
|
honkar-jdk
left a comment
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.
Please update the copyright year for .cpp file.
Is there a way to test this fix or possibly add a test case?
| try { | ||
| m_hIcon = CreateIconFromRaster(env, iconRaster, w, h); | ||
| JNU_CHECK_EXCEPTION(env); // Might throw here | ||
| m_hIconSm = CreateIconFromRaster(env, smallIconRaster, smw, smh); | ||
| JNU_CHECK_EXCEPTION(env); // Or here | ||
| } catch (...) { |
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.
At first I thought using C++ exception handling was a bad idea, but it's actually needed. The code in CreateIconFromRaster can throw a C++ exception, specifically BitmapUtil::CreateTransparencyMaskFromARGB and BitmapUtil::CreateV4BitmapFromARGB.
jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp
Lines 2075 to 2087 in e413fc6
| try { | |
| iconRasterBuffer = (int *)env->GetPrimitiveArrayCritical(iconRaster, 0); | |
| JNI_CHECK_NULL_GOTO(iconRasterBuffer, "iconRaster data", done); | |
| mask = BitmapUtil::CreateTransparencyMaskFromARGB(w, h, iconRasterBuffer); | |
| image = BitmapUtil::CreateV4BitmapFromARGB(w, h, iconRasterBuffer); | |
| } catch (...) { | |
| if (iconRasterBuffer != NULL) { | |
| env->ReleasePrimitiveArrayCritical(iconRaster, iconRasterBuffer, 0); | |
| } | |
| throw; | |
| } |
Since the exception is re-thrown in the handler there, it has to be caught in AwtWindow::SetIconData. Yet you shouldn't re-throw the C++ exception here, it must not escape JNI code, otherwise, the unhandled exception will likely crash the Java process.
|
|
||
| try { | ||
| m_hIcon = CreateIconFromRaster(env, iconRaster, w, h); | ||
| JNU_CHECK_EXCEPTION(env); // Might throw here |
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.
The comment is misleading, JNU_CHECK_EXCEPTION does not throw an exception.
jdk/src/java.base/share/native/libjava/jni_util.h
Lines 278 to 283 in 27646e5
| #define JNU_CHECK_EXCEPTION(env) \ | |
| do { \ | |
| if ((env)->ExceptionCheck()) { \ | |
| return; \ | |
| } \ | |
| } while (0) \ |
It checks if an exception is raised in Java code and returns immediately if there's a pending Java exception.
If a Java exception is raised at this line, after m_hIcon is assigned and its value is not NULL, it has to be deleted.
Perhaps, you have to handle it explicitly here:
if (env->ExceptionCheck()) {
if (m_hIcon) {
DestroyIcon(m_hIcon);
}
return;
}It looks that the original values stored in hOldIcon and hOldIconSm should be restored if an error occurs.
| m_hIcon = CreateIconFromRaster(env, iconRaster, w, h); | ||
| JNU_CHECK_EXCEPTION(env); // Might throw here | ||
| m_hIconSm = CreateIconFromRaster(env, smallIconRaster, smw, smh); | ||
| JNU_CHECK_EXCEPTION(env); // Or here |
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.
The clean-up code here should delete both m_hIcon and m_hIconSm.
And restore the previous values?
| if (m_hIconSm != NULL) { | ||
| DestroyIcon(m_hIconSm); | ||
| } | ||
| throw; // Re-throw the exception |
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.
The C++ exception shouldn't be re-thrown here.
Whether we should raise a Java exception to indicate an error is to be discussed. If we restore the state of the AwtWindow object as if no failure occurred, it can continue. And I don't see any meaningful way to return an error back to Java here.
CreateIconFromRaster throws NullPointerException if it fails to get the image raster.
jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp
Lines 2076 to 2078 in e413fc6
| iconRasterBuffer = (int *)env->GetPrimitiveArrayCritical(iconRaster, 0); | |
| JNI_CHECK_NULL_GOTO(iconRasterBuffer, "iconRaster data", done); |
where JNI_CHECK_NULL_GOTO is
jdk/src/java.desktop/windows/native/libawt/windows/awt.h
Lines 48 to 54 in 27646e5
| #define JNI_CHECK_NULL_GOTO(obj, msg, where) { \ | |
| if (obj == NULL) { \ | |
| env->ExceptionClear(); \ | |
| JNU_ThrowNullPointerException(env, msg); \ | |
| goto where; \ | |
| } \ | |
| } |
|
The suggested fix does not address the reported issue yet: both Based on my above comments, I suggest restructuring the code.
|
aivanov-jdk
left a comment
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.
Looks good to me except for a tiny formatting nit.
@honkar-jdk I don't think it's possible to write a test for this case…. It my be tested by defining Another way could be to change the source code to explicitly cause |
@aivanov-jdk Thanks for clarifying. |
prrace
left a comment
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.
Although this leak is extremely unlikely, leaks of GDI resources can bring even a modern windows system to its knees in a matter of seconds ..
| { | ||
| HICON hNewIcon = NULL; | ||
| HICON hNewIconSm = NULL; | ||
|
|
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.
I presume we know for sure there's no exception pending when we enter ?
Looking at the only caller, it seems probable.
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.
Are you suggesting we add a JNU_CHECK_EXCEPTION the beginning of the function? , as I don't think we know for sure there is an exception pending or not at this point.
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.
I presume we know for sure there's no exception pending when we enter ?
Looking at the only caller, it seems probable.
There can't be a pending exception when AwtWindow::SetIconData starts.
The chain starts with JNI method Java_sun_awt_windows_WWindowPeer_setIconImagesData which calls AwtWindow::_SetIconImagesData wrapped in SyncCall.
No Java code is called before execution gets into SetIconData where CreateIconFromRaster is called.
…I don't think we know for sure there is an exception pending or not at this point.
I'm sure there's no pending exception on the entry to AwtWindow::SetIconData.
| HICON hOldIcon = NULL; | ||
| HICON hOldIconSm = NULL; | ||
| //Destroy previous icon if it isn't inherited | ||
| if ((m_hIcon != NULL) && !m_iconInherited) { |
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.
I am not sure why the check for NULL is needed .. but it is OK.
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.
What do you mean? That it could've been just if ((m_hIcon) && !m_iconInherited)?
This line is unchanged.
In the majority of cases the surrounding code uses explicit != NULL in if-statements.
|
While I was looking deeper into the code flow, I found another place which needs changing. jdk/src/java.desktop/windows/native/libawt/windows/awt_Taskbar.cpp Lines 126 to 132 in 0fbf10a
The JNI method The call to I think it's reasonable to address this new issue under a new bugid. |
I submitted JDK-8282862: Catch C++ exception in Java_sun_awt_windows_WTaskbarPeer_setOverlayIcon. |
|
/integrate |
|
/sponsor |
|
Going to push as commit 48ece07.
Your commit was automatically rebased without conflicts. |
|
@aivanov-jdk @rajamah Pushed as commit 48ece07. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Issue:
AwtWindow::SetIconData leaks the old icon handles in hOldIcon and hOldIconSm if CreateIconFromRaster raises an exception. Additionally, an exception is checked only after the first call to CreateIconFromRaster.
Solution:
I have added the exception handling code to take care that the handles are properly destroyed and not leaked.
Testing:
I have tested the code to make sure there are no regressions caused by this.
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/22932/head:pull/22932$ git checkout pull/22932Update a local copy of the PR:
$ git checkout pull/22932$ git pull https://git.openjdk.org/jdk.git pull/22932/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 22932View PR using the GUI difftool:
$ git pr show -t 22932Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/22932.diff
Using Webrev
Link to Webrev Comment