1 /*
2  * Copyright (c) 2019, 2021, 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  * @requires vm.flavor != "zero"
29  * @summary Check that SIGBUS errors caused by memory accesses in Unsafe_CopyMemory()
30  * and UnsafeCopySwapMemory() get converted to java.lang.InternalError exceptions.
31  * @modules java.base/jdk.internal.misc
32  *          java.base/java.nio:+open
33  *
34  * @library /test/lib
35  * @build sun.hotspot.WhiteBox
36  * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
37  *
38  * @run main/othervm -XX:CompileCommand=exclude,*InternalErrorTest.main -XX:CompileCommand=inline,*.get -XX:CompileCommand=inline,*Unsafe.* -Xbootclasspath/a:.  -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI InternalErrorTest
39  */
40 
41 import java.io.File;
42 import java.io.IOException;
43 import java.io.RandomAccessFile;
44 import java.lang.reflect.Field;
45 import java.lang.reflect.Method;
46 import java.nio.MappedByteBuffer;
47 import java.nio.channels.FileChannel;
48 import java.nio.file.Files;
49 import jdk.internal.misc.Unsafe;
50 import sun.hotspot.WhiteBox;
51 
52 // Test that illegal memory access errors in Unsafe_CopyMemory0() and
53 // UnsafeCopySwapMemory() that cause SIGBUS errors result in
54 // java.lang.InternalError exceptions, not JVM crashes.
55 public class InternalErrorTest {
56 
57     private static final Unsafe unsafe = Unsafe.getUnsafe();
58     private static final int pageSize = WhiteBox.getWhiteBox().getVMPageSize();
59     private static final String expectedErrorMsg = "fault occurred in a recent unsafe memory access";
60     private static final String failureMsg1 = "InternalError not thrown";
61     private static final String failureMsg2 = "Wrong InternalError: ";
62 
main(String[] args)63     public static void main(String[] args) throws Throwable {
64         Unsafe unsafe = Unsafe.getUnsafe();
65 
66         String currentDir = System.getProperty("test.classes");
67         File file = new File(currentDir, "tmpFile.txt");
68 
69         StringBuilder s = new StringBuilder();
70         for (int i = 1; i < pageSize + 1000; i++) {
71             s.append("1");
72         }
73         Files.write(file.toPath(), s.toString().getBytes());
74         FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel();
75         MappedByteBuffer buffer =
76             fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
77 
78         // Get address of mapped memory.
79         long mapAddr = 0;
80         try {
81             Field af = java.nio.Buffer.class.getDeclaredField("address");
82             af.setAccessible(true);
83             mapAddr = af.getLong(buffer);
84         } catch (Exception f) {
85             throw f;
86         }
87         long allocMem = unsafe.allocateMemory(4000);
88 
89         for (int i = 0; i < 3; i++) {
90             test(buffer, unsafe, mapAddr, allocMem, i);
91         }
92 
93         Files.write(file.toPath(), "2".getBytes());
94         buffer.position(buffer.position() + pageSize);
95         for (int i = 0; i < 3; i++) {
96             try {
97                 test(buffer, unsafe, mapAddr, allocMem, i);
98                 WhiteBox.getWhiteBox().forceSafepoint();
99                 throw new RuntimeException(failureMsg1);
100             } catch (InternalError e) {
101                 if (!e.getMessage().contains(expectedErrorMsg)) {
102                     throw new RuntimeException(failureMsg2 + e.getMessage());
103                 }
104             }
105         }
106 
107         Method m = InternalErrorTest.class.getMethod("test", MappedByteBuffer.class, Unsafe.class, long.class, long.class, int.class);
108         WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 3);
109 
110         for (int i = 0; i < 3; i++) {
111             try {
112                 test(buffer, unsafe, mapAddr, allocMem, i);
113                 WhiteBox.getWhiteBox().forceSafepoint();
114                 throw new RuntimeException(failureMsg1);
115             } catch (InternalError e) {
116                 if (!e.getMessage().contains(expectedErrorMsg)) {
117                     throw new RuntimeException(failureMsg2 + e.getMessage());
118                 }
119             }
120         }
121 
122         WhiteBox.getWhiteBox().enqueueMethodForCompilation(m, 4);
123 
124         for (int i = 0; i < 3; i++) {
125             try {
126                 test(buffer, unsafe, mapAddr, allocMem, i);
127                 WhiteBox.getWhiteBox().forceSafepoint();
128                 throw new RuntimeException(failureMsg1);
129             } catch (InternalError e) {
130                 if (!e.getMessage().contains(expectedErrorMsg)) {
131                     throw new RuntimeException(failureMsg2 + e.getMessage());
132                 }
133             }
134         }
135 
136         System.out.println("Success");
137     }
138 
test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, long allocMem, int type)139     public static void test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, long allocMem, int type) {
140         switch (type) {
141             case 0:
142                 // testing Unsafe.copyMemory, trying to access a word from next page after truncation.
143                 buffer.get(new byte[8]);
144                 break;
145             case 1:
146                 // testing Unsafe.copySwapMemory, trying to access next  page after truncation.
147                 unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], 16, 2000, 2);
148                 break;
149             case 2:
150                 // testing Unsafe.copySwapMemory, trying to access next  page after truncation.
151                 unsafe.copySwapMemory(null, mapAddr + pageSize, null, allocMem, 2000, 2);
152                 break;
153         }
154     }
155 
156 }
157