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