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

Paul Sandoz paul.sandoz at oracle.com
Wed Jan 10 22:36:23 UTC 2024


Hi Roman,

You found an embarrassing bug.

For now please replace the call to byteVec.fromMemorySegment with 

  ByteVector.fromMemorySegment(byteVec, …);

The reason for the crash is the call to byteVec.fromMemorySegment is not performing any bounds checks! 
Oops, dunno how we missed that. We need to fix that, The call on species should route through to the static call ByteVector.fromMemorySegment) as in the array access cases.

In your code your index value is an int and the upper bound is a long, so at some point the index will overflow to a large native value, which is not checked and results in a SEGV.

Paul.

> On Jan 10, 2024, at 1:18 PM, Roman Stoffel <roman.stoffel at gamlor.info> wrote:
> 
> 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
> 



More information about the panama-dev mailing list