Java 17 bug (?) on Windows with MemorySegment.asSlice and offset =
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu May 12 11:19:35 UTC 2022
I've reproduced on Windows.
One thing I noticed is that using file sizes that are a power of two
will get rid of errors.
So, using this:
```
raf.setLength(1L << 33); //~8gb
```
Works w/o any issues.
I think I managed to get to the bottom of it. I started looking at how
mapped files were implemented on Windows, and I notice that
CreateFileMapping do not accept (unlike Linux mmap) a 8-byte value for
the size/offset. Instead, they split the 8-byte value into two DWORDs
(high and low). That said, that logic seemed to be handled correctly in
the JDK code:
```
jlong maxSize = off + len;
jint lowLen = (jint)(maxSize);
jint highLen = (jint)(maxSize >> 32);
```
But on Windows, you first get a map handle, and _then_ you get a map
"view". To get the map view, you have to specify a size again, but this
time the size is a SIZE_T; this is _not_ handled correcty in the JDK:
```
mapAddress = MapViewOfFile(
mapping, /* Handle of file mapping object */
mapAccess, /* Read and write access */
highOffset, /* High word of offset */
lowOffset, /* Low word of offset */
(DWORD)len); /* Number of bytes to map */ <------
```
That cast seems questionable, as DWORD is 32-bit, so casting an 8-byte
value bigger than 2^32 into that will surely fail.
Of course, this was never an issue with ByteBuffer, as you could never
create such a big memory mapped region. But with memory segments this
becomes problematic.
Fixing the cast to use SIZE_T instead solves the issue you are seeing.
Thanks
Maurizio
On 12/05/2022 10:54, Maurizio Cimadamore wrote:
> I have spotted something...
>
> The code that creates a mapped buffer is like this:
>
> ```
> return Util.newMappedByteBufferR((int)unmapper.cap,
> unmapper.address + unmapper.pagePosition,
> unmapper.fd,
> unmapper, isSync);
> ```
>
> While the code that creates the mapped segment is like this:
>
> ```
> AbstractMemorySegmentImpl segment = new
> MappedMemorySegmentImpl(unmapper.address(), unmapper, size,
> modes, session);
> ```
>
> While the two are similar, there are some differences:
>
> * the BB version is using unmapper.cap for the size, while the segment
> version is just passing the size - on further inspection, this
> difference seems benign, as unmapper.cap seems to be always set to the
> user specified byte size
> * the BB address is set to unmapper.address + pagePosition - now this
> is an actual difference between the two snippets - the memory segment
> version ignores pagePosition.
>
> The second difference seems like a bug - that said, it should only
> manifest when mapping a file with a non-zero offset, as pagePosition
> is computed as follows:
>
> ```
> pagePosition = (int)(position % allocationGranularity);
> ```
>
> (where `position` is really the memory mapped offset). That is, if the
> specified offset is zero, the base address of the mapped segment
> should always be page-aligned.
>
> So, I don't think this issue, alone, (while a bug) is enough to
> explain what's going on.
>
> Maurizio
>
>
> On 12/05/2022 10:32, Maurizio Cimadamore wrote:
>> Uhm... this seems worse.
>>
>> Something seems to point at the spatial bounds of the segment not
>> being set correctly.
>>
>> Maurizio
>>
>> On 12/05/2022 09:45, erel at eth.gl wrote:
>>> (sorry for the frequent messages)
>>>
>>>
>>> In the previous example the exception was thrown from the “force”
>>> call. A low level error happens with similar code:
>>>
>>> long offset = 3704800000L;
>>>
>>> ByteBuffer bb = ByteBuffer.allocateDirect(100000);
>>>
>>> MemorySegment mbb = MemorySegment.ofByteBuffer(bb);
>>>
>>> while (true) {
>>>
>>> System.out.println("offset: " + offset);
>>>
>>> MemorySegment target =
>>> mappedMemorySegment.asSlice(offset, 100000);
>>>
>>> offset = offset + 100000;
>>>
>>> target.copyFrom(mbb);
>>>
>>> }
>>>
>>>
>>> Output:
>>>
>>>
>>> WARNING: Using incubator modules: jdk.incubator.foreign
>>>
>>> 64
>>>
>>> amd64
>>>
>>> 17.0.3.1
>>>
>>> byteSize: 8000000000
>>>
>>> offset: 3704800000
>>>
>>> offset: 3704900000
>>>
>>> offset: 3705000000
>>>
>>> #
>>>
>>> # A fatal error has been detected by the Java Runtime Environment:
>>>
>>> #
>>>
>>> # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000027a6c4f4176,
>>> pid=16060, tid=2208
>>>
>>> #
>>>
>>> # JRE version: Java(TM) SE Runtime Environment (17.0.3.1+2) (build
>>> 17.0.3.1+2-LTS-6)
>>>
>>> # Java VM: Java HotSpot(TM) 64-Bit Server VM (17.0.3.1+2-LTS-6,
>>> mixed mode, sharing, tiered, compressed oops, compressed class ptrs,
>>> g1 gc, windows-amd64)
>>>
>>> # Problematic frame:
>>>
>>> # v ~StubRoutines::jlong_disjoint_arraycopy
>>>
>>> #
>>>
>>> # No core dump will be written. Minidumps are not enabled by default
>>> on client versions of Windows
>>>
>>> #
>>>
>>> # An error report file with more information is saved as:
>>>
>>> # …\hs_err_pid16060.log
>>>
>>> #
>>>
>>> # If you would like to submit a bug report, please visit:
>>>
>>> # https://bugreport.java.com/bugreport/crash.jsp
>>>
>>> #
>>>
>>>
More information about the panama-dev
mailing list