-
Notifications
You must be signed in to change notification settings - Fork 5.9k
8296496: Overzealous check in sizecalc.h prevents large memory allocation #11030
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
Instead cast the parameters to type_t just the way they are treated in the existing size check macro. Since this checking maccro was used in couple of different places all of them needs to be updated.
👋 Welcome back kizune! A progress list of the required criteria for merging this PR into |
@azuev-java The following label 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 list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
@aivanov-jdk @azvegint @prrace please review |
|
||
#define SAFE_SIZE_NEW_ARRAY2(type, n, m) \ | ||
(IS_SAFE_SIZE_MUL((m), (n)) && IS_SAFE_SIZE_MUL(sizeof(type), (n) * (m)) ? \ | ||
(new type[(n) * (m)]) : throw std::bad_alloc()) | ||
(new type[(size_t)((n) * (m))]) : throw std::bad_alloc()) |
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.
(new type[(size_t)((n) * (m))]) : throw std::bad_alloc()) | |
(new type[(size_t)(n) * (size_t)(m)]) : throw std::bad_alloc()) |
Each parameter must be cast as in SAFE_SIZE_ARRAY_ALLOC
.
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.
Each parameter must be cast as in SAFE_SIZE_ARRAY_ALLOC.
If we do that then logic might be broken since we checking for the limits against the (size_t)(m * n) but performing call with ((size_t)(m) * (size_t)(n)) which might add potential point of failure. I prefer to do the conversions in the same way we do them in checks.
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.
It's what you just did for SAFE_SIZE_ARRAY_ALLOC
:
#define SAFE_SIZE_ARRAY_ALLOC(func, m, n) \
- (IS_SAFE_SIZE_MUL((m), (n)) ? ((func)((m) * (n))) : FAILURE_RESULT)
+ (IS_SAFE_SIZE_MUL((m), (n)) ? ((func)((size_t)(m) * (size_t)(n))) : FAILURE_RESULT)
You cast both m
and n
.
This code basically does the same. If you don't cast each parameter, the result may be different, since there are cases where ((size_t)(m) * (size_t)(n))
is not equal to (size_t)((m) * (n))
.
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.
Ok, i see what you mean. Ok, that might work since we are already checking SAFE_SIZE_MUL((m), (n)) in the line above.
@@ -116,7 +112,7 @@ | |||
* // Use the allocated memory... | |||
*/ | |||
#define SAFE_SIZE_STRUCT_ALLOC(func, a, m, n) \ | |||
(IS_SAFE_STRUCT_SIZE((a), (m), (n)) ? ((func)((a) + (m) * (n))) : FAILURE_RESULT) | |||
(IS_SAFE_STRUCT_SIZE((a), (m), (n)) ? ((func)((a) + (size_t)(m) * (size_t)(n))) : FAILURE_RESULT) |
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.
(IS_SAFE_STRUCT_SIZE((a), (m), (n)) ? ((func)((a) + (size_t)(m) * (size_t)(n))) : FAILURE_RESULT) | |
(IS_SAFE_STRUCT_SIZE((a), (m), (n)) ? ((func)((size_t)(a) + (size_t)(m) * (size_t)(n))) : FAILURE_RESULT) |
To be safe, a
should also be cast.
And IS_SAFE_STRUCT_SIZE
should also be updated to pass (size_t)(m) * (size_t)(n)
to IS_SAFE_SIZE_ADD
instead of (m) * (n)
.
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.
To be safe,
a
should also be cast.And IS_SAFE_STRUCT_SIZE should also be updated to pass (size_t)(m) * (size_t)(n) to IS_SAFE_SIZE_ADD instead of (m) * (n).
Sounds reasonable.
Mailing list message from Aleksei Ivanov on client-libs-dev: Hi Patrick, It is the reason why it should be updated. The checks in What if ?a? is a signed integer with negative value? Regards, On 08/11/2022 15:25, Patrick Chen wrote: |
@azuev-java 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 124 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. ➡️ To integrate this PR with the above commit message to the |
Mailing list message from Patrick Chen on client-libs-dev: But you forgot that (IS_SAFE_STRUCT_SIZE((a), (m), (n)) ? ((func)((a) + Le mar. 8 nov. 2022 ? 14:59, Alexey Ivanov <aivanov at openjdk.org> a ?crit : -------------- next part -------------- |
/integrate |
Going to push as commit 84e1224.
Your commit was automatically rebased without conflicts. |
@azuev-java Pushed as commit 84e1224. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
@@ -92,19 +88,19 @@ | |||
* IS_SAFE_... macros to check if the calculations are safe. | |||
*/ | |||
#define SAFE_SIZE_NEW_ARRAY(type, n) \ | |||
(IS_SAFE_SIZE_MUL(sizeof(type), (n)) ? (new type[(n)]) : throw std::bad_alloc()) | |||
(IS_SAFE_SIZE_MUL(sizeof(type), (n)) ? (new type[(size_t)(n)]) : throw std::bad_alloc()) | |||
|
|||
#define SAFE_SIZE_NEW_ARRAY2(type, n, m) \ | |||
(IS_SAFE_SIZE_MUL((m), (n)) && IS_SAFE_SIZE_MUL(sizeof(type), (n) * (m)) ? \ |
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.
Why we do not cast it here: (n) * (m)?
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 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're right, it must be cast here too, I have missed it.
Would you mind submitting a bug?
Removed the additional multiplication overflow detection.
Instead cast all the parameters to type_t just the way they are treated in the existing size check macro.
This way there is no possibility to accidentally provide parameters that will pass the size check macro while being cast to size_t there but then due to the missing cast cause the wrong size passed the actual allocation function.
Since this checking macro was used in couple of different places all of them needs to be updated in the similar way.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/11030/head:pull/11030
$ git checkout pull/11030
Update a local copy of the PR:
$ git checkout pull/11030
$ git pull https://git.openjdk.org/jdk pull/11030/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 11030
View PR using the GUI difftool:
$ git pr show -t 11030
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/11030.diff