1 /*
2  * Copyright (c) 1999, 2018, 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 
26 /*
27  * @test
28  * @key stress
29  *
30  * @summary converted from VM testbase nsk/stress/except/except007.
31  * VM testbase keywords: [stress, diehard, slow, nonconcurrent, quick]
32  * VM testbase readme:
33  * DESCRIPTION
34  *     This checks if various exceptions are thrown (and caught) correctly
35  *     when there apparently are no free space in the heap to allocate new
36  *     Throwable instance.
37  *     The test tries to occupy all of memory available in the heap by allocating
38  *     lots of new Object() instances. Instances of the type Object are the smallest
39  *     objects, so they apparently should occupy most fine-grained fragments in the
40  *     heap and leave no free space for new Throwable instance. After that, the test
41  *     provokes various exceptions (e.g.: by executing integer division by 0 and so
42  *     on), and checks if appropriate exceptions are thrown.
43  * COMMENTS
44  *     The test needs a lot of memory to start up, so it should not run under older
45  *     JDK 1.1.x release due to its poorer heap utilization. Also, some checks are
46  *     skipped when testing classic VM, because OutOfMemoryError is correctly thrown
47  *     instead of target exception.
48  *     When the test is being self-initiating (i.e.: eating heap), memory occupation
49  *     is terminated if memory allocation slows down crucially. This is a workaround
50  *     intended to avoid the HotSpot bug:
51  *         #4248801 (P1/S5) slow memory allocation when heap is almost exhausted
52  *     There is also a workaround involved to avoid the following bugs known
53  *     for HotSpot and for classic VM:
54  *         #4239841 (P1/S5) 1.1: poor garbage collector performance  (HotSpot bug)
55  *         #4245060 (P4/S5) poor garbage collector performance       (Classic VM bug)
56  *     However, printing of the test's error messages, warnings, and of execution
57  *     trace fails under JDK 1.2 for Win32 even so. If the test fails due to this
58  *     problem, exit status 96 is returned instead of 97.
59  *     JDK 1.3 classic VM for Sparc may crash (core dump) due to the known bug:
60  *         #4245057 (P2/S3) VM crashes when heap is exhausted
61  *
62  * @run main/othervm -Xms50M -Xmx200M nsk.stress.except.except007
63  */
64 
65 package nsk.stress.except;
66 
67 import java.io.PrintStream;
68 
69 /**
70  * This checks if various exceptions are thrown (and caught) correctly
71  * when there apparently are no free space in the heap to allocate new
72  * <code>Throwable</code> instance.
73  * <p>
74  * <p>The test tries to occupy all of memory available in the heap by
75  * allocating lots of new <code>Object()</code> instances. Instances of the
76  * type <code>Object</code> are the smallest objects, so they apparently should
77  * occupy most fine-grained fragments in the heap and leave no free space for
78  * new <code>Throwable</code> instance. After that, the test provokes various
79  * exceptions (e.g.: by executing integer division by 0 and so on), and checks
80  * if appropriate exceptions are thrown.
81  * <p>
82  * <p>Note, that memory occupation is terminated if memory allocation slows
83  * down crucially. This is a workaround intended to avoid the HotSpot bug:
84  * <br>&nbsp;&nbsp;
85  * #4248801 (P1/S5) slow memory allocation when heap is almost exhausted
86  * <p>
87  * <p>There is also a workaround involved to avoid the following bugs known
88  * for HotSpot and for classic VM:
89  * <br>&nbsp;&nbsp;
90  * #4239841 (P1/S5) 1.1: poor garbage collector performance
91  * <br>&nbsp;&nbsp;
92  * #4245060 (P4/S5) poor garbage collector performance
93  * <br>However, printing of the test's error messages, warnings, and of
94  * execution trace may fail even so. If the test fails due to poor GC
95  * performance, exit status 96 is returned instead of 97.
96  * <p>
97  * <p>Also note, that the test needs a lot of memory to start up, so it should
98  * not run under older JDK 1.1.x release due to its poor heap utilization.
99  */
100 public class except007 {
101     /**
102      * Either allow or supress printing of execution trace.
103      */
104     private static boolean TRACE_ON = false;
105     /**
106      * Either allow or supress printing of warning messages.
107      */
108     private static final boolean WARN_ON = true;
109     /*
110      * Storage for a lot of tiny objects
111      * "static volatile" keywords are for preventing heap optimization
112      */
113     private static volatile Object pool[] = null;
114     /**
115      * Temporary <code>log</code> for error messages, warnings and/or execution trace.
116      *
117      * @see #messages
118      */
119     private static String log[] = new String[1000]; // up to 1000 messages
120     /**
121      * How many <code>messages</code> were submitted to the <code>log</code>.
122      *
123      * @see #log
124      */
125     private static int messages = 0;
126 
127     /**
128      * Re-call to the method <code>run(out)</code> (ignore <code>args[]</code>),
129      * and print the test summary - either test passed of failed.
130      */
run(String args[], PrintStream out)131     public static int run(String args[], PrintStream out) {
132         if (args.length > 0) {
133             if (args[0].toLowerCase().startsWith("-v"))
134                 TRACE_ON = true;
135         }
136 
137         int exitCode = run(out);
138         pool = null;
139         System.gc();
140         // Print the log[] and the test summary:
141         try {
142             for (int i = 0; i < messages; i++)
143                 out.println(log[i]);
144             if (exitCode == 0) {
145                 if (TRACE_ON)
146                     out.println("Test passed.");
147             } else
148                 out.println("Test failed.");
149         } catch (OutOfMemoryError oome) {
150             // Poor performance of garbage collector:
151             exitCode = 1;
152         }
153 
154         return exitCode;
155     }
156 
157     /**
158      * Allocate as much <code>Object</code> instances as possible to bring JVM
159      * into stress, and then check if exceptions are correctly thrown accordingly
160      * to various situations like integer division by 0, etc.
161      */
run(PrintStream out)162     private static int run(PrintStream out) {
163         out.println("# While printing this message, JVM seems to initiate the output");
164         out.println("# stream, so that it will not need more memory to print later,");
165         out.println("# when the heap would fail to provide more memory.");
166         out.println("# ");
167         out.println("# Note, that the test maintains especial static log[] field in");
168         out.println("# order to avoid printing when the heap seems exhausted.");
169         out.println("# Nevertheless, printing could arise OutOfMemoryError even");
170         out.println("# after all the memory allocated by the test is released.");
171         out.println("# ");
172         out.println("# That problem is caused by the known JDK/HotSpot bugs:");
173         out.println("#     4239841 (P1/S5) 1.1: poor garbage collector performance");
174         out.println("#     4245060 (P4/S5) poor garbage collector performance");
175         out.println("# ");
176         out.println("# This message is just intended to work-around that problem.");
177         out.println("# If printing should fail even so, the test will try to return");
178         out.println("# the exit status 96 instead of 97 to indicate the problem.");
179         out.println("# However, the test may fail or even crash on some platforms");
180         out.println("# suffering the bug 4239841 or 4245060.");
181 
182         // Prepare some items, which will be used by the test:
183         Thread rabbit = new Rabbit();
184 
185         // Allocate repository for a lots of tiny objects:
186         for (int size = 1 << 30; size > 0 && pool == null; size >>= 1)
187             try {
188                 pool = new Object[size];
189             } catch (OutOfMemoryError oome) {
190             }
191         if (pool == null)
192             throw new Error("HS bug: cannot allocate new Object[1]");
193         int poolSize = pool.length;
194 
195         int index = 0;
196         pool[index++] = new Object();
197 
198         // Sum up time spent, when it was hard to JVM to allocate next object
199         // (i.e.: when JVM has spent more than 1 second to allocate new object):
200         double totalDelay = 0;
201         long timeMark = System.currentTimeMillis();
202         try {
203             for (; index < poolSize; index++) {
204                 //-------------------------
205                 pool[index] = new Object();
206                 long nextTimeMark = System.currentTimeMillis();
207                 long elapsed = nextTimeMark - timeMark;
208                 timeMark = nextTimeMark;
209                 //----------------------
210                 if (elapsed > 1000) {
211                     double seconds = elapsed / 1000.0;
212                     if (TRACE_ON)
213                         out.println(
214                                 "pool[" + index + "]=new Object(); // elapsed " + seconds + "s");
215                     totalDelay += seconds;
216                     if (totalDelay > 60) {
217                         if (TRACE_ON)
218                             out.println(
219                                     "Memory allocation became slow; so, heap seems exhausted.");
220                         break;
221                     }
222                 }
223             }
224         } catch (OutOfMemoryError oome) {
225             if (TRACE_ON)
226                 log[messages++] = "Heap seems exhausted - OutOfMemoryError thrown.";
227         }
228         if (index > poolSize - 1000) {
229             if (WARN_ON)
230                 log[messages++] = "Warning: pool[] is full; so, checks would not be enough hard...";
231         }
232 
233         // Sum up exit code:
234         int exitCode = 0; // apparently PASSED
235         int skipped = 0;  // some checks may correctly suffer OutOfMemoryError
236 
237         // Check InterruptedException:
238         try {
239             synchronized (rabbit) {
240                 rabbit.start();
241                 rabbit.wait();
242             }
243             rabbit.interrupt();
244             while (rabbit.isAlive())
245                 rabbit.join();
246             Throwable exception = ((Rabbit) rabbit).exception;
247             if (exception == null) {
248                 log[messages++] = "Failure: InterruptedException not thrown";
249                 exitCode = 2;
250             } else {
251                 if (exception instanceof InterruptedException) {
252                     if (TRACE_ON)
253                         log[messages++] =
254                                 "Success: InterruptedException thrown as expected";
255                 } else if (exception instanceof OutOfMemoryError) {
256                     if (WARN_ON)
257                         log[messages++] = "Skipped: InterruptedException";
258                     skipped++;
259                 } else {
260                     log[messages++] =
261                             "Failure: InterruptedException: unexpected exception thrown";
262                     exitCode = 2;
263                 }
264                 pool[index++] = exception;
265             }
266         } catch (InterruptedException ie) {
267             log[messages++] = "Failure: InterruptedException thrown unexpectedly";
268             exitCode = 2;
269         } catch (OutOfMemoryError oome) {
270             if (WARN_ON)
271                 log[messages++] = "Skipped: InterruptedException";
272             skipped++;
273         }
274 
275         // Check NegativeArraySizeException:
276         try {
277             int negative = -1;
278             byte array[] = new byte[negative];
279             log[messages++] = "Failure: NegativeArraySizeException not thrown as expected";
280             exitCode = 2;
281         } catch (NegativeArraySizeException ie) {
282             if (TRACE_ON)
283                 log[messages++] = "Success: NegativeArraySizeException thrown as expected";
284             pool[index++] = ie;
285         } catch (OutOfMemoryError oome) {
286             if (WARN_ON)
287                 log[messages++] = "Skipped: NegativeArraySizeException";
288             skipped++;
289         }
290 
291         // Check NullPointerException:
292         try {
293             Double none = null;
294             double oops = none.doubleValue();
295             log[messages++] = "Failure: NullPointerException not thrown as expected";
296             exitCode = 2;
297         } catch (NullPointerException npe) {
298             if (TRACE_ON)
299                 log[messages++] = "Success: NullPointerException thrown as expected";
300             pool[index++] = npe;
301         } catch (OutOfMemoryError oome) {
302             if (WARN_ON)
303                 log[messages++] = "Skipped: NullPointerException";
304             skipped++;
305         }
306 
307         // Check NumberFormatException:
308         try {
309             double oops = Double.parseDouble("3.14159D00"); // FORTRAN-like
310             log[messages++] = "Failure: NumberFormatException not thrown as expected";
311             exitCode = 2;
312         } catch (NumberFormatException nfe) {
313             if (TRACE_ON)
314                 log[messages++] = "Success: NumberFormatException thrown as expected";
315         } catch (OutOfMemoryError oome) {
316             if (WARN_ON)
317                 log[messages++] = "Skipped: NumberFormatException";
318             skipped++;
319         }
320 
321         return exitCode;
322     }
323 
324     /**
325      * Will shoot a rabbit when it waits -- in order to provoke
326      * InterruptedException.
327      */
328     private static class Rabbit extends Thread {
329         Throwable exception = null;
330 
run()331         public void run() {
332             try {
333                 synchronized (this) {
334                     this.notify();
335                     this.wait();
336                 }
337             } catch (InterruptedException ie) {
338                 exception = ie;
339             } catch (OutOfMemoryError oome) {
340                 exception = oome;
341             }
342         }
343 
344     }
345 
346     /**
347      * Re-call to <code>run(args,out)</code>, and return JCK-like exit status.
348      * (The stream <code>out</code> is assigned to <code>System.out</code> here.)
349      *
350      * @see #run(String[], PrintStream)
351      */
main(String args[])352     public static void main(String args[]) {
353         Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
354             // Last try. If there is some exception outside the code, test should end correctly
355             @Override
356             public void uncaughtException(Thread t, Throwable e) {
357                 try {
358                     pool = null;
359                     log = null;
360                     System.gc();
361                     if (e instanceof OutOfMemoryError) {
362                         try {
363                             System.out.println("OOME : Test Skipped");
364                             System.exit(0);
365                         } catch (Throwable ignore) {
366                         } // No code in the handler can provoke correct exceptions.
367                     } else {
368                         e.printStackTrace();
369                         throw (RuntimeException) e;
370                     }
371                 } catch (OutOfMemoryError oome) {
372                 }
373             }
374         });
375         int exitCode = run(args, System.out);
376         System.exit(exitCode + 95);
377         // JCK-like exit status.
378     }
379 
380 }
381