jdk-24/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java
2024-09-27 08:28:59 +00:00

166 lines
6.7 KiB
Java

/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8191278
* @requires os.family != "windows"
* @requires vm.flavor != "zero"
* @summary Check that SIGBUS errors caused by memory accesses in Unsafe_CopyMemory()
* and UnsafeCopySwapMemory() get converted to java.lang.InternalError exceptions.
* @modules java.base/jdk.internal.misc
* java.base/java.nio:+open
*
* @library /test/lib
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
*
* @run main/othervm -XX:CompileCommand=exclude,*InternalErrorTest.main -XX:CompileCommand=inline,*.get -XX:CompileCommand=inline,*Unsafe.* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI InternalErrorTest
*/
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.foreign.MemorySegment;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import jdk.internal.misc.Unsafe;
import jdk.test.whitebox.WhiteBox;
// Test that illegal memory access errors in Unsafe_CopyMemory0() and
// UnsafeCopySwapMemory() that cause SIGBUS errors result in
// java.lang.InternalError exceptions, not JVM crashes.
public class InternalErrorTest {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int pageSize = WhiteBox.getWhiteBox().getVMPageSize();
private static final String expectedErrorMsg = "fault occurred in an unsafe memory access";
private static final String failureMsg1 = "InternalError not thrown";
private static final String failureMsg2 = "Wrong InternalError: ";
private static final int NUM_TESTS = 4;
public static void main(String[] args) throws Throwable {
Unsafe unsafe = Unsafe.getUnsafe();
String currentDir = System.getProperty("test.classes");
File file = new File(currentDir, "tmpFile.txt");
StringBuilder s = new StringBuilder();
for (int i = 1; i < pageSize + 1000; i++) {
s.append("1");
}
Files.write(file.toPath(), s.toString().getBytes());
FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();
MappedByteBuffer buffer =
fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size());
// Get address of mapped memory.
long mapAddr = 0;
try {
Field af = java.nio.Buffer.class.getDeclaredField("address");
af.setAccessible(true);
mapAddr = af.getLong(buffer);
} catch (Exception f) {
throw f;
}
long allocMem = unsafe.allocateMemory(4000);
for (int i = 0; i < NUM_TESTS; i++) {
test(buffer, unsafe, mapAddr, allocMem, i);
}
Files.write(file.toPath(), "2".getBytes());
buffer.position(buffer.position() + pageSize);
for (int i = 0; i < NUM_TESTS; i++) {
try {
test(buffer, unsafe, mapAddr, allocMem, i);
WhiteBox.getWhiteBox().forceSafepoint();
throw new RuntimeException(failureMsg1);
} catch (InternalError e) {
if (!e.getMessage().contains(expectedErrorMsg)) {
throw new RuntimeException(failureMsg2 + e.getMessage());
}
}
}
Method m = InternalErrorTest.class.getMethod("test", MappedByteBuffer.class, Unsafe.class, long.class, long.class, int.class);
WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 3);
for (int i = 0; i < NUM_TESTS; i++) {
try {
test(buffer, unsafe, mapAddr, allocMem, i);
WhiteBox.getWhiteBox().forceSafepoint();
throw new RuntimeException(failureMsg1);
} catch (InternalError e) {
if (!e.getMessage().contains(expectedErrorMsg)) {
throw new RuntimeException(failureMsg2 + e.getMessage());
}
}
}
WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 4);
for (int i = 0; i < NUM_TESTS; i++) {
try {
test(buffer, unsafe, mapAddr, allocMem, i);
WhiteBox.getWhiteBox().forceSafepoint();
throw new RuntimeException(failureMsg1);
} catch (InternalError e) {
if (!e.getMessage().contains(expectedErrorMsg)) {
throw new RuntimeException(failureMsg2 + e.getMessage());
}
}
}
System.out.println("Success");
}
public static void test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, long allocMem, int type) {
switch (type) {
case 0:
// testing Unsafe.copyMemory, trying to access a word from next page after truncation.
buffer.get(new byte[8]);
break;
case 1:
// testing Unsafe.copySwapMemory, trying to access next page after truncation.
int destOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], destOffset, 2000, 2);
break;
case 2:
// testing Unsafe.copySwapMemory, trying to access next page after truncation.
unsafe.copySwapMemory(null, mapAddr + pageSize, null, allocMem, 2000, 2);
break;
case 3:
MemorySegment segment = MemorySegment.ofBuffer(buffer);
// testing Unsafe.setMemory, trying to access next page after truncation.
segment.fill((byte) 0xF0);
break;
}
}
}