Hi Maurizio,
On 24/01/2020 9:27 am, Maurizio Cimadamore wrote:
On 23/01/2020 22:59, David Holmes wrote:
On 24/01/2020 12:41 am, Andrew Haley wrote:
On 1/23/20 10:22 AM, David Holmes wrote:
That aside IIRC the overflow check is not ideal here because we already
enter undefined behaviour territory inside align_up if we actually
overflow.
How is that possible? size_t is an unsigned type, and unsigned types
never overflow.
Yes you are right, I was not recalling the rules correctly. So the
addition to the size_t is guaranteed to wrap and so the < test is valid.
Sorry for the noise on that.
It may still be cleaner if the Java side enforces a maximum of
Integer.MAX_VALUE for 32-bit.
I have no objections in adding an extra check where the native memory
segment is created - perhaps we should just do that.
That said, memory segments are not the only clients of
Unsafe::allocateMemory - so if we decided that overflow is an issue that
should be handled in clients, fine, but at least it should be evident
somewhere in the javadoc of Unsafe::allocateMemory?
I'm glad you raised that as it prompted me to examine Unsafe in more
detail. :)
The onus is put on the caller to ensure arguments are valid. Unsafe
class docs state, and a number of methods like allocateMemory repeat:
* <em>Note:</em> It is the resposibility of the caller to make
* sure arguments are checked before the methods are called. While
* some rudimentary checks are performed on the input, the checks
* are best effort and when performance is an overriding priority,
* as when methods of this class are optimized by the runtime
* compiler, some or all checks (if any) may be elided. Hence, the
* caller must not rely on the checks and corresponding
* exceptions!
So although allocateMemory explicitly checks for size_t related overflow:
* @throws RuntimeException if the size is negative or too large
* for the native size_t type
the caller should not be relying on that.
The existing overflow check is done by checkSize(long size) which has:
if (ADDRESS_SIZE == 4) {
// Note: this will also check for negative sizes
if (!is32BitClean(size)) {
throw invalidInput();
}
}
where is32BitClean is defined as:
value >>> 32 == 0;
and so is incomplete as this doesn't take into account the possible
align up of "size" that the JVM allocation routine actually performs.
But even if we fix this, the caller is not supposed to rely on it.
In terms of fixing it ... it isn't clear to me whether this case should
be detected in the VM as Nick's patch does, or whether it should be
caught before hand in the checkSize Java code (though we don't really
know what the alignment requirement may be in the Java code). A
difference is that if we catch it in checkSize then we will throw
IllegalArgumentException, whereas Nick's approach results in
OutOfMemoryError. I think the IllegalArgumentException is actually
preferable here.
David
-----
Maurizio
Thanks,
David
On a 32-bit box, 0 <= size < 2**32. So -- in theory at
least -- you could allocate more than 2G.