1 /* 2 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8191278 27 * @requires os.family != "windows" 28 * @summary Check that SIGBUS errors caused by memory accesses in Unsafe_CopyMemory() 29 * and UnsafeCopySwapMemory() get converted to java.lang.InternalError exceptions. 30 * @modules java.base/jdk.internal.misc 31 * java.base/java.nio:+open 32 * 33 * @library /test/lib 34 * @build sun.hotspot.WhiteBox 35 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 36 * 37 * @run main/othervm -XX:CompileCommand=exclude,*InternalErrorTest.main -XX:CompileCommand=inline,*.get -XX:CompileCommand=inline,*Unsafe.* -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI InternalErrorTest 38 */ 39 40 import java.io.File; 41 import java.io.IOException; 42 import java.io.RandomAccessFile; 43 import java.lang.reflect.Field; 44 import java.lang.reflect.Method; 45 import java.nio.MappedByteBuffer; 46 import java.nio.channels.FileChannel; 47 import java.nio.file.Files; 48 import jdk.internal.misc.Unsafe; 49 import sun.hotspot.WhiteBox; 50 51 // Test that illegal memory access errors in Unsafe_CopyMemory0() and 52 // UnsafeCopySwapMemory() that cause SIGBUS errors result in 53 // java.lang.InternalError exceptions, not JVM crashes. 54 public class InternalErrorTest { 55 56 private static final Unsafe unsafe = Unsafe.getUnsafe(); 57 private static final int pageSize = WhiteBox.getWhiteBox().getVMPageSize(); 58 private static final String expectedErrorMsg = "fault occurred in a recent unsafe memory access"; 59 private static final String failureMsg1 = "InternalError not thrown"; 60 private static final String failureMsg2 = "Wrong InternalError: "; 61 main(String[] args)62 public static void main(String[] args) throws Throwable { 63 Unsafe unsafe = Unsafe.getUnsafe(); 64 65 String currentDir = System.getProperty("test.classes"); 66 File file = new File(currentDir, "tmpFile.txt"); 67 68 StringBuilder s = new StringBuilder(); 69 for (int i = 1; i < pageSize + 1000; i++) { 70 s.append("1"); 71 } 72 Files.write(file.toPath(), s.toString().getBytes()); 73 FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel(); 74 MappedByteBuffer buffer = 75 fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); 76 77 // Get address of mapped memory. 78 long mapAddr = 0; 79 try { 80 Field af = java.nio.Buffer.class.getDeclaredField("address"); 81 af.setAccessible(true); 82 mapAddr = af.getLong(buffer); 83 } catch (Exception f) { 84 throw f; 85 } 86 long allocMem = unsafe.allocateMemory(4000); 87 88 for (int i = 0; i < 3; i++) { 89 test(buffer, unsafe, mapAddr, allocMem, i); 90 } 91 92 Files.write(file.toPath(), "2".getBytes()); 93 buffer.position(buffer.position() + pageSize); 94 for (int i = 0; i < 3; i++) { 95 try { 96 test(buffer, unsafe, mapAddr, allocMem, i); 97 WhiteBox.getWhiteBox().forceSafepoint(); 98 throw new RuntimeException(failureMsg1); 99 } catch (InternalError e) { 100 if (!e.getMessage().contains(expectedErrorMsg)) { 101 throw new RuntimeException(failureMsg2 + e.getMessage()); 102 } 103 } 104 } 105 106 Method m = InternalErrorTest.class.getMethod("test", MappedByteBuffer.class, Unsafe.class, long.class, long.class, int.class); 107 WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 3); 108 109 for (int i = 0; i < 3; i++) { 110 try { 111 test(buffer, unsafe, mapAddr, allocMem, i); 112 WhiteBox.getWhiteBox().forceSafepoint(); 113 throw new RuntimeException(failureMsg1); 114 } catch (InternalError e) { 115 if (!e.getMessage().contains(expectedErrorMsg)) { 116 throw new RuntimeException(failureMsg2 + e.getMessage()); 117 } 118 } 119 } 120 121 WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 4); 122 123 for (int i = 0; i < 3; i++) { 124 try { 125 test(buffer, unsafe, mapAddr, allocMem, i); 126 WhiteBox.getWhiteBox().forceSafepoint(); 127 throw new RuntimeException(failureMsg1); 128 } catch (InternalError e) { 129 if (!e.getMessage().contains(expectedErrorMsg)) { 130 throw new RuntimeException(failureMsg2 + e.getMessage()); 131 } 132 } 133 } 134 135 System.out.println("Success"); 136 } 137 test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, long allocMem, int type)138 public static void test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, long allocMem, int type) { 139 switch (type) { 140 case 0: 141 // testing Unsafe.copyMemory, trying to access a word from next page after truncation. 142 buffer.get(new byte[8]); 143 break; 144 case 1: 145 // testing Unsafe.copySwapMemory, trying to access next page after truncation. 146 unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], 16, 2000, 2); 147 break; 148 case 2: 149 // testing Unsafe.copySwapMemory, trying to access next page after truncation. 150 unsafe.copySwapMemory(null, mapAddr + pageSize, null, allocMem, 2000, 2); 151 break; 152 } 153 } 154 155 } 156