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
8283225: ClassLoader.c produces incorrect OutOfMemory Exception when length is 0 (aix) #7829
Conversation
|
@backwaterred The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
Hi Tyler,
The way we solve this usually is by homogenizing malloc behavior across all platforms with if (len == 0) len=1;
, see e.g.
jdk/src/hotspot/share/runtime/os.cpp
Lines 644 to 647 in 08cadb4
// On malloc(0), implementators of malloc(3) have the choice to return either | |
// NULL or a unique non-NULL pointer. To unify libc behavior across our platforms | |
// we chose the latter. | |
size = MAX2((size_t)1, size); |
I suggest you do that here too since it would be a far less intrusive change. If you don't want to fix up all three malloc call sites, just reroute them to a local malloc stub (my_malloc()
) that corrects length and calls the real malloc. If you want, you can #ifdef _AIX
that length correction too, e.g.:
static void* my_malloc(size_t l) {
#ifdef _AIX
if (l == 0) l = 1;
#endif
return malloc(l);
}
That would be a far smaller change, and it would not introduce a new behavioral difference (because with your change, AIX now throws ClassFormatError where other platforms don't).
Side note: nothing against changing 0 to NULL, but please in a separate cleanup patch.
Cheers, Thomas
Btw, which malloc call was the problematic exactly? Cannot be the one in getUTF, since that one already adds len + 1 and never gets called with a zero length anyway. |
Oh, good point. I guess it gets lost in the noise of my other changes. The lines causing the issue was these ones: jdk/src/java.base/share/native/libjava/ClassLoader.c Lines 102 to 107 in 08cadb4
|
Interesting! That idea didn't occur to me until after I submitted the PR. I'm happy to test that out and see how it works. |
Thanks @tstuefe! Your suggestion lead to a better change, so I modified the PR.
Note: I couldn't find an implementation of MAX2 in a C-friendly 'header.h' file, so I just used the ternary operator in the two places I needed it. |
I just saw this. I will separate the cleanup into a separate patch. |
- Changes malloc(0) call to malloc(1) on AIX.
The requested changes have been made, and a better, leaner PR results. In addition to the changes mentioned above, I also incorporated Thomas' suggestion to use |
@backwaterred This change now passes all automated pre-integration checks. 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 33 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 (@tstuefe, @RogerRiggs, @dholmes-ora) but any other Committer may sponsor as well.
|
p.s. this issue puts the finger on a sore point. We have corrected mallocs in the JDK in a number of places, e.g. in libverify: ( jdk/src/java.base/share/native/libverify/check_code.c Lines 91 to 102 in 3da5204
(which is also strictly speaking incorrect since the spec says to return a non-unique pointer). More generally, we have with AIX the problem that APIs have different behavior than the more usual nixes or are missing, and we need a porting layer to provide missing or change different APIs. Beside AIX-ish malloc, one example is dladdr, which is missing. In hotspot, we have os/aix, so we are fine. See If you find a way to commonize that code across JDK libraries, that would be cool. I even thought about providing a porting library completely independent from the OpenJDK itself, more like a system library. We did this for our internal iSeries port but the logistics were annoying, so we did not do it for AIX. But you at IBM may have a better idea. Cheers, Thomas |
- Reword to avoid double use of malloc(X) - Remove bug id
/integrate |
@backwaterred |
Update looks good. Sorry for the AIX_ONLY misdirect.
Thanks,
David
/sponsor |
It would be real nice to have the same set of macros in JDK too, though. |
Going to push as commit cab4ff6.
Your commit was automatically rebased without conflicts. |
@tstuefe @backwaterred Pushed as commit cab4ff6. |
@@ -99,7 +99,12 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, | |||
return 0; | |||
} | |||
|
|||
// On AIX malloc(0) returns NULL which looks like an out-of-memory condition; so adjust it to malloc(1) | |||
#ifdef _AIX | |||
body = (jbyte *)malloc(length == 0 ? 1 : length); |
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.
Can we use identification in the ifdef/else/endif block to make it a bit more readable. Also can you trim down the comment or split it over two lines to avoid the really long line (it makes it a bit easier for future side-by-side reviews).
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 can split down the comment if you prefer. It might be appropriate to do in the as-yet-unmerged cleanup PR I have open for the same file.
I am not sure what you mean by 'use identification'. Can you clarify?
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 think it’s a typo of “indentation”, e.g.:
body = (jbyte *)malloc(length == 0 ? 1 : length); | |
body = (jbyte *)malloc(length == 0 ? 1 : length); |
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.
Ah, that does make sense. Please request these changes here and I am happy to make them.
As described in the linked issue, NullClassBytesTest fails due an OutOfMemoryError produced on AIX when the test calls defineClass with a byte array of size of 0. The native implementation of defineClass then calls malloc with a size of 0. On AIX malloc(0) returns NULL, while on other platforms it return a valid address. When NULL is produced by malloc for this reason, ClassLoader.c incorrectly interprets this as a failure due to a lack of memory.
This PR modifies ClassLoader.c to produce an OutOfMemoryError only when[edit: The above no longer describes the PR's proposed fix. See discussion below]errno == ENOMEM
and to produce a ClassFormatError with the message "ClassLoader internal allocation failure" in all other cases (in which malloc returns NULL).In addition, I performed some minor tidy-up work in ClassLoader.c by changing instances of
return 0
toreturn NULL
, andif (some_ptr == 0)
toif (some_ptr == NULL)
. This was done to improve the clarity of the code in ClassLoader.c, but didn't feel worthy of opening a separate issue.Alternatives
It would be possible to address this failure by modifying the test to accept the OutOfMemoryError on AIX. I thought it was a better solution to modify ClassLoader.c to produce an OutOfMemoryError only when the system is actually out of memory.
Testing
This change has been tested on AIX and Linux/x86.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/7829/head:pull/7829
$ git checkout pull/7829
Update a local copy of the PR:
$ git checkout pull/7829
$ git pull https://git.openjdk.java.net/jdk pull/7829/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 7829
View PR using the GUI difftool:
$ git pr show -t 7829
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/7829.diff