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