/* * 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; } } }