1 /*
2 * Copyright (c) 2015, 2016, 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 */
95 * Potential stack overflows are detected by stack banging,
96 * at method invocation time.
97 * In interpreted code, the stack banging performed for the
98 * lock() method goes further than the stack banging performed
99 * for the getter or the setter method, so the potential stack
100 * overflow is detected before entering the critical section.
101 * In compiled code, the getter and the setter are in-lined,
102 * so the stack banging is only performed before entering the
103 * critical section.
104 * In order to have a stack banging that goes further for the
105 * getter/setter methods than for the lock() method, the test
106 * exploits the property that interpreter frames are (much)
107 * bigger than compiled code frames. When the test is run,
108 * a compiler option disables the compilation of the
109 * setExclusiveOwnerThread() method.
110 *
111 */
112
113 import java.util.concurrent.locks.ReentrantLock;
114 import jdk.test.lib.Platform;
115
116 public class ReservedStackTest {
117
118 static class ReentrantLockTest {
119
120 private ReentrantLock lockArray[];
121 // Frame sizes vary a lot between interpreted code and compiled code
122 // so the lock array has to be big enough to cover all cases.
123 // If test fails with message "Not conclusive test", try to increase
124 // LOCK_ARRAY_SIZE value
125 private static final int LOCK_ARRAY_SIZE = 8192;
126 private boolean stackOverflowErrorReceived;
127 StackOverflowError soe = null;
128 private int index = -1;
129
130 public void initialize() {
131 lockArray = new ReentrantLock[LOCK_ARRAY_SIZE];
132 for (int i = 0; i < LOCK_ARRAY_SIZE; i++) {
133 lockArray[i] = new ReentrantLock();
134 }
180 int testStartFrame;
181 ReentrantLockTest test;
182
183 public RunWithSOEContext(ReentrantLockTest test, int deframe) {
184 this.test = test;
185 this.deframe = deframe;
186 }
187
188 @Override
189 @jdk.internal.vm.annotation.ReservedStackAccess
190 public void run() {
191 counter = 0;
192 decounter = deframe;
193 test.initialize();
194 recursiveCall();
195 System.out.println("Framework got StackOverflowError at frame = " + counter);
196 System.out.println("Test started execution at frame = " + (counter - deframe));
197 String result = test.getResult();
198 // The feature is not fully implemented on all platforms,
199 // corruptions are still possible.
200 boolean supportedPlatform =
201 Platform.isAix() ||
202 (Platform.isLinux() &&
203 (Platform.isPPC() || Platform.isS390x() || Platform.isX64() ||
204 Platform.isX86() || Platform.isAArch64())) ||
205 Platform.isOSX() ||
206 Platform.isSolaris();
207 if (supportedPlatform && !result.contains("PASSED")) {
208 System.out.println(result);
209 throw new Error(result);
210 } else {
211 // Either the test passed or this platform is not supported.
212 // On not supported platforms, we only expect the VM to
213 // not crash during the test. This is especially important
214 // on Windows where the detection of SOE in annotated
215 // sections is implemented but the reserved zone mechanism
216 // to avoid the corruption cannot be implemented yet
217 // because of JDK-8067946
218 System.out.println("PASSED");
219 }
220 }
221
222 void recursiveCall() {
223 // Unused local variables to increase the frame size
224 long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19;
225 long l20, l21, l22, l23, l24, l25, l26, l27, l28, l30, l31, l32, l33, l34, l35, l36, l37;
226 counter++;
227 try {
228 recursiveCall();
229 } catch (StackOverflowError e) {
230 }
231 decounter--;
232 if (decounter == 0) {
233 setupSOEFrame = counter;
234 testStartFrame = counter - deframe;
235 test.run();
236 }
237 }
238 }
239
240 public static void main(String[] args) {
241 for (int i = 0; i < 1000; i++) {
242 // Each iteration has to be executed by a new thread. The test
243 // relies on the random size area pushed by the VM at the beginning
244 // of the stack of each Java thread it creates.
245 Thread thread = new Thread(new RunWithSOEContext(new ReentrantLockTest(), 256));
246 thread.start();
247 try {
248 thread.join();
249 } catch (InterruptedException ex) { }
250 }
251 }
252 }
|
1 /*
2 * Copyright (c) 2015, 2017, 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 */
95 * Potential stack overflows are detected by stack banging,
96 * at method invocation time.
97 * In interpreted code, the stack banging performed for the
98 * lock() method goes further than the stack banging performed
99 * for the getter or the setter method, so the potential stack
100 * overflow is detected before entering the critical section.
101 * In compiled code, the getter and the setter are in-lined,
102 * so the stack banging is only performed before entering the
103 * critical section.
104 * In order to have a stack banging that goes further for the
105 * getter/setter methods than for the lock() method, the test
106 * exploits the property that interpreter frames are (much)
107 * bigger than compiled code frames. When the test is run,
108 * a compiler option disables the compilation of the
109 * setExclusiveOwnerThread() method.
110 *
111 */
112
113 import java.util.concurrent.locks.ReentrantLock;
114 import jdk.test.lib.Platform;
115 import jdk.test.lib.process.ProcessTools;
116 import jdk.test.lib.process.OutputAnalyzer;
117
118 public class ReservedStackTest {
119
120 static class ReentrantLockTest {
121
122 private ReentrantLock lockArray[];
123 // Frame sizes vary a lot between interpreted code and compiled code
124 // so the lock array has to be big enough to cover all cases.
125 // If test fails with message "Not conclusive test", try to increase
126 // LOCK_ARRAY_SIZE value
127 private static final int LOCK_ARRAY_SIZE = 8192;
128 private boolean stackOverflowErrorReceived;
129 StackOverflowError soe = null;
130 private int index = -1;
131
132 public void initialize() {
133 lockArray = new ReentrantLock[LOCK_ARRAY_SIZE];
134 for (int i = 0; i < LOCK_ARRAY_SIZE; i++) {
135 lockArray[i] = new ReentrantLock();
136 }
182 int testStartFrame;
183 ReentrantLockTest test;
184
185 public RunWithSOEContext(ReentrantLockTest test, int deframe) {
186 this.test = test;
187 this.deframe = deframe;
188 }
189
190 @Override
191 @jdk.internal.vm.annotation.ReservedStackAccess
192 public void run() {
193 counter = 0;
194 decounter = deframe;
195 test.initialize();
196 recursiveCall();
197 System.out.println("Framework got StackOverflowError at frame = " + counter);
198 System.out.println("Test started execution at frame = " + (counter - deframe));
199 String result = test.getResult();
200 // The feature is not fully implemented on all platforms,
201 // corruptions are still possible.
202 if (isSupportedPlatform && !result.contains("PASSED")) {
203 System.out.println(result);
204 throw new Error(result);
205 } else {
206 // Either the test passed or this platform is not supported.
207 // On not supported platforms, we only expect the VM to
208 // not crash during the test. This is especially important
209 // on Windows where the detection of SOE in annotated
210 // sections is implemented but the reserved zone mechanism
211 // to avoid the corruption cannot be implemented yet
212 // because of JDK-8067946
213 System.out.println("PASSED");
214 }
215 }
216
217 void recursiveCall() {
218 // Unused local variables to increase the frame size
219 long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19;
220 long l20, l21, l22, l23, l24, l25, l26, l27, l28, l30, l31, l32, l33, l34, l35, l36, l37;
221 counter++;
222 try {
223 recursiveCall();
224 } catch (StackOverflowError e) {
225 }
226 decounter--;
227 if (decounter == 0) {
228 setupSOEFrame = counter;
229 testStartFrame = counter - deframe;
230 test.run();
231 }
232 }
233 }
234
235 public static boolean isAlwaysSupportedPlatform() {
236 // Note: To date Aarch64 is the only platform that we don't statically
237 // know if it supports the reserved stack area. This is because the
238 // open Aarch64 port supports it and the Oracle arm64 port does not.
239 return Platform.isAix() ||
240 (Platform.isLinux() &&
241 (Platform.isPPC() || Platform.isS390x() || Platform.isX64() ||
242 Platform.isX86())) ||
243 Platform.isOSX() ||
244 Platform.isSolaris();
245 }
246
247 public static boolean isNeverSupportedPlatform() {
248 return !isAlwaysSupportedPlatform() && !Platform.isAArch64();
249 }
250
251 public static boolean isSupportedPlatform;
252
253 public static void initIsSupportedPlatform() throws Exception {
254 // In order to dynamicaly determine if the platform supports the reserved
255 // stack area, run with -XX:StackReservedPages=1 and see if we get the
256 // expected warning message for platforms that don't support it.
257 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:StackReservedPages=1", "-version");
258 OutputAnalyzer output = new OutputAnalyzer(pb.start());
259 System.out.println("StackReservedPages=1 log: [" + output.getOutput() + "]");
260 if (output.getExitValue() != 0) {
261 String msg = "Could not launch with -XX:StackReservedPages=1: exit " + output.getExitValue();
262 System.err.println("FAILED: " + msg);
263 throw new RuntimeException(msg);
264 }
265
266 isSupportedPlatform = true;
267 String matchStr = "Reserved Stack Area not supported on this platform";
268 int match_idx = output.getOutput().indexOf(matchStr);
269 if (match_idx >= 0) {
270 isSupportedPlatform = false;
271 }
272
273 // Do a sanity check. Some platforms we know are always supported. Make sure
274 // we didn't determine that one of those platforms is not supported.
275 if (!isSupportedPlatform && isAlwaysSupportedPlatform()) {
276 String msg = "This platform should be supported: " + Platform.getOsArch();
277 System.err.println("FAILED: " + msg);
278 throw new RuntimeException(msg);
279 }
280
281 // And some platforms we know are never supported. Make sure
282 // we didn't determine that one of those platforms is supported.
283 if (isSupportedPlatform && isNeverSupportedPlatform()) {
284 String msg = "This platform should not be supported: " + Platform.getOsArch();
285 System.err.println("FAILED: " + msg);
286 throw new RuntimeException(msg);
287 }
288 }
289
290 public static void main(String[] args) throws Exception {
291 initIsSupportedPlatform();
292 for (int i = 0; i < 1000; i++) {
293 // Each iteration has to be executed by a new thread. The test
294 // relies on the random size area pushed by the VM at the beginning
295 // of the stack of each Java thread it creates.
296 Thread thread = new Thread(new RunWithSOEContext(new ReentrantLockTest(), 256));
297 thread.start();
298 try {
299 thread.join();
300 } catch (InterruptedException ex) { }
301 }
302 }
303 }
|