9003e2c519
Reviewed-by: aboldtch, coleenp
166 lines
6.7 KiB
Java
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;
|
|
}
|
|
}
|
|
|
|
}
|