JVM SIGSEGV when accessing out of bound MemorySegment via SIMD Vector(JDK 21)

Roman Stoffel roman.stoffel at gamlor.info
Wed Jan 10 21:18:39 UTC 2024


Hello

I've gotten a segfault when accessing MemorySegments via SIMD Vector out of
bounds in JDK 21.
The repro is:
- Read from a MemorySegment via Vector.fromMemorySegment.
- Ensure the code get hot enough
- Walk of the boundary of the MemorySegment
- Results in SIGSEGV

I'm mostly posting in here just in case. Here is my repro:

import jdk.incubator.vector.ByteVector;
import jdk.incubator.vector.Vector;
import jdk.incubator.vector.VectorSpecies;

import java.io.IOException;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Random;

public class SegFaultRepro {
    private static final Path file = Paths.get("example.bin");
    public static void main(String[] args) throws IOException {
        // File needs to be large enough: To get the code hot enough to be
C2 compiled. Increase if JVM does not crash
        final long LARGE_FILE_SEG_FAULTS = 200_000;
        final long SMALL_FILE_WORKS = 100;
        setupTest(LARGE_FILE_SEG_FAULTS);
        VectorSpecies<Byte> byteVec = ByteVector.SPECIES_PREFERRED;

        try{
            Vector<Byte> blackhole = byteVec.zero();
            try(var arena = Arena.ofConfined();
                FileChannel fc = FileChannel.open(file)){
                MemorySegment fileContent =
fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size(), arena);
                // -Alternative 2: Also segfaults: Needs way larger memory
area on my machine
                // MemorySegment fileContent =
arena.allocate(1_000_000L*4096L);
                // - Alternative 3: Works as expected? Couldn't get a crash
yet.
                //   Maybe because I can't get a large enough memory
section in this basic example
                // MemorySegment fileContent = MemorySegment.ofArray(new
byte[Integer.MAX_VALUE-1024]);
                long fileSize = fileContent.byteSize();

                int i = 0;
                while(i<byteVec.loopBound(fileSize)){
                    int offByOneError = i + 1;
                    Vector<Byte> read =
byteVec.fromMemorySegment(fileContent, offByOneError, ByteOrder.BIG_ENDIAN);
                    blackhole = blackhole.add(read);
                    i+= byteVec.length();
                }
            }
            System.out.println(blackhole.toString());
        } catch (IndexOutOfBoundsException e){
            System.out.println("All good. We have a off by one error and
got an Exception for it.");
        }
    }
    private static void setupTest(long LARGE_FILE_SEG_FAULTS) throws
IOException {
        final long fileSize = LARGE_FILE_SEG_FAULTS;
        byte[] exampleData = new byte[4096];
        new Random().nextBytes(exampleData);
        try (var out = Files.newOutputStream(file)) {
            for (int i = 0; i < fileSize; i++) {
                out.write(exampleData);
            }
        }
        System.out.println("Example file created!");
    }
}



Notes:
- Running on x86-64bit linux.
- Crashes only on hot loop
- Works best with Memory Mapped files for me. Probably because it changes
the timing / slows down the memory access to give C2 time to compile.
- I can reproduce it with an Arena.allocate Memory segment as well =).
- Could not reproduce it with a Memory


Best regards
Roman Stoffel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20240110/ec912700/attachment.htm>


More information about the panama-dev mailing list