RFR: 8281213: Unsafe uses of long and size_t in MemReporterBase::diff_in_current_scale [v3]
Evgeny Astigeevich
eastigeevich at openjdk.org
Mon Dec 19 14:06:53 UTC 2022
On Sat, 17 Dec 2022 10:15:31 GMT, Afshin Zafari <duke at openjdk.org> wrote:
>> ### Description
>> MemReporterBase::diff_in_current_scale is defined as follows:
>>
>> inline long diff_in_current_scale(size_t s1, size_t s2) const {
>> long amount = (long)(s1 - s2);
>> long scale = (long)_scale;
>> amount = (amount > 0) ? (amount + scale / 2) : (amount - scale / 2);
>> return amount / scale;
>> }
>>
>> Long and size_t can have different sizes: 4 bytes and 8 bytes (LLP64). The result of 's1 - s2' might not fit into long. It might not fit into int64_t. For example: s1 is SIZE_MAX and s2 is SIZE_MAX-MAX_INT64-1.
>>
>> Size_t should be used instead of long. Assertions must be added to check:
>> s1 >= s2 and (amount - scale/2) >= 0 and (amount + scale/2) <= SIZE_MAX.
>>
>> ### Patch
>> `long` is replaced by `size_t`. Comparison to 0 is implemented accordingly since size_t is always >= 0.
>> Since s1 can be less than s2 in some invocations of this method, no assert is written for `(s1 >= s2)` case.
>>
>> ### Test
>> local: runtime/NMT/Jcmd*
>> mach5: tier1
>
> Afshin Zafari has updated the pull request incrementally with one additional commit since the last revision:
>
> 8281213: Unsafe uses of long and size_t in MemReporterBase::diff_in_current_scale
src/hotspot/share/services/memReporter.hpp line 82:
> 80: assert(amount <= SIZE_MAX - _scale / 2, "size_t overflow");
> 81: amount = (amount + _scale / 2) / _scale;
> 82: // We assume the valid range for deltas [INT64_MIN, INT64_MAX] to simplify the code.
In the assert the comment should be:
We assume the valid range for deltas [-INT64_MAX, INT64_MAX] to simplify the code.
I excluded the `INT64_MIN` case to simplify the code.
The `INT64_MIN` case is when `sizeof(size_t) == sizeof(int64_t) && amount == INT64_MAX + 1 && is_negative == true`.
For this case `-(int64_t)amount` is UB which needs proper handling.
The code instead of
return (is_negative) ? -(int64_t)amount : (int64_t)amount;
would be more complex:
if (!is_negative) {
return (int64_t)amount;
} else {
return (amount != INT64_MAX+1) ? -(int64_t)amount : INT64_MIN;
}
This is why the assert part is `sizeof(size_t) == sizeof(int64_t) && amount <= INT64_MAX)`
Maybe the better comment is
// We assume the valid range for deltas [-INT64_MAX, INT64_MAX].
// We excluded the `INT64_MIN` case to simplify the code.
src/hotspot/share/services/memReporter.hpp line 83:
> 81: amount = (amount + _scale / 2) / _scale;
> 82: // We assume the valid range for deltas [INT64_MIN, INT64_MAX] to simplify the code.
> 83: assert((sizeof(size_t) < sizeof(int64_t)) || (sizeof(size_t) == sizeof(int64_t) && amount <= INT64_MAX), "cannot fit scaled diff into size_t");
Maybe this would be better:
"scaled diff is out of supported range [-INT64_MAX, INT64_MAX]"
-------------
PR: https://git.openjdk.org/jdk/pull/11514
More information about the hotspot-runtime-dev
mailing list