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