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/except004.
  30  * VM testbase keywords: [stress, diehard, 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 -XX:-UseGCOverheadLimit nsk.stress.except.except004
  62  */
  63 
  64 package nsk.stress.except;
  65 
  66 import java.io.PrintStream;
  67 import java.lang.reflect.Field;
  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 except004 {
 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      */
 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;
 138         try {
 139             exitCode = run(out);
 140         } finally { // ensure we have free memory for exception processing
 141             pool = null;
 142             System.gc();
 143         }
 144         if (TRACE_ON)
 145             out.println("Test completed.");
 146 
 147         // Print the log[] and the test summary:
 148         try {
 149             for (int i = 0; i < messages; i++)
 150                 out.println(log[i]);
 151             if (exitCode == 0) {
 152                 if (TRACE_ON)
 153                     out.println("Test passed.");
 154             } else
 155                 out.println("Test failed.");
 156         } catch (OutOfMemoryError oome) {
 157             // Poor performance of garbage collector:
 158             exitCode = 1;
 159         }
 160 
 161         return exitCode;
 162     }
 163 
 164     /**
 165      * Allocate as much <code>Object</code> instances as possible to bring JVM
 166      * into stress, and then check if exceptions are correctly thrown accordingly
 167      * to various situations like integer division by 0, etc.
 168      */
 169     private static int run(PrintStream out) {
 170         out.println("# While printing this message, JVM seems to initiate the output");
 171         out.println("# stream, so that it will not need more memory to print later,");
 172         out.println("# when the heap would fail to provide more memory.");
 173         out.println("# ");
 174         out.println("# Note, that the test maintains especial static log[] field in");
 175         out.println("# order to avoid printing when the heap seems exhausted.");
 176         out.println("# Nevertheless, printing could cause OutOfMemoryError even");
 177         out.println("# after all the memory allocated by the test is released.");
 178         out.println("# ");
 179         out.println("# That problem is caused by the known JDK/HotSpot bugs:");
 180         out.println("#     4239841 (P1/S5) 1.1: poor garbage collector performance");
 181         out.println("#     4245060 (P4/S5) poor garbage collector performance");
 182         out.println("# ");
 183         out.println("# This message is just intended to work-around that problem.");
 184         out.println("# If printing should fail even so, the test will return the");
 185         out.println("# exit status 96 instead of 97 to indicate the problem.");
 186 
 187         // run all tests normally to ensure all needed classes are loaded and
 188         // initialized before the heap is exhausted - else we may trigger OOME
 189         // in unexpected places.
 190         try {
 191             if (TRACE_ON)
 192                 out.println("Running without heap exhaustion");
 193             runTests(out, false);
 194         } catch (Throwable unexpected) {
 195             out.println("Test pre-initialisation failed: " + unexpected);
 196             return 2;
 197         }
 198 
 199         if (TRACE_ON)
 200             out.println("Running with heap exhaustion");
 201 
 202         return runTests(out, true);
 203     }
 204 
 205     private static int runTests(PrintStream out, boolean exhaustHeap) {
 206         // reset message index
 207         messages = 0;
 208 
 209         // Prepare some items, which will be used by the test:
 210         Object stringArray[] = new String[1];
 211         Object integerValue = new Integer(0);
 212         Object doubleValue = new Double(0);
 213         Object trash = null;
 214         Field abraPrivateField;
 215         Field abraIntegerField;
 216         Field abraBooleanField;
 217         try {
 218             abraPrivateField = Abra.class.getDeclaredField("DONT_TOUCH_ME");
 219             abraIntegerField = Abra.class.getDeclaredField("MAIN_CYR_NUMBER");
 220             abraBooleanField = Abra.class.getDeclaredField("NOT_AN_INTEGER");
 221         } catch (NoSuchFieldException nsfe) {
 222             out.println("Test initialisation failed: field not found in class Abra");
 223             return 2;
 224         }
 225 
 226         Abra abra = new Abra("via public constructor");
 227         Abra.Cadabra cadabra = new Abra.Cadabra();
 228         // Sum up exit code:
 229         int exitCode = 0; // apparently PASSED
 230         int skipped = 0;  // some checks may correctly suffer OutOfMemoryError
 231 
 232         int poolSize = 0;
 233         int index = 0;
 234 
 235         if (exhaustHeap) {
 236             pool = null;
 237             // Allocate repository for lots of tiny objects:
 238             for (int size = 1 << 30; size > 0 && pool == null; size >>= 1) {
 239                 try {
 240                     pool = new Object[size];
 241                 } catch (OutOfMemoryError oome) {
 242                 }
 243             }
 244             if (pool == null)
 245                 throw new Error("HS bug: cannot allocate new Object[1]");
 246             poolSize = pool.length;
 247             index = 0;
 248 
 249             // Sum up time spent, when it was hard for JVM to allocate next object
 250             // (i.e.: when JVM has spent more than 1 second to allocate new object):
 251             double totalDelay = 0;
 252             long timeMark = System.currentTimeMillis();
 253             try {
 254                 for (; index < poolSize; index++) {
 255                     //-------------------------
 256                     pool[index] = new Object();
 257                     long nextTimeMark = System.currentTimeMillis();
 258                     long elapsed = nextTimeMark - timeMark;
 259                     timeMark = nextTimeMark;
 260                     //----------------------
 261                     if (elapsed > 1000) {
 262                         double seconds = elapsed / 1000.0;
 263                         if (TRACE_ON)
 264                             out.println(
 265                                     "pool[" + index + "]=new Object(); // elapsed " + seconds + "s");
 266                         totalDelay += seconds;
 267                         if (totalDelay > 60) {
 268                             if (TRACE_ON)
 269                                 out.println(
 270                                         "Memory allocation became slow; so, heap seems exhausted.");
 271                             break;
 272                         }
 273                     }
 274                 }
 275             } catch (OutOfMemoryError oome) {
 276                 if (TRACE_ON)
 277                     log[messages++] = "Heap seems exhausted - OutOfMemoryError thrown.";
 278                 // Do not release any byte once allocated:
 279                 pool[index++] = oome;
 280             }
 281 
 282             if (index > poolSize - 1000) {
 283                 if (WARN_ON)
 284                     log[messages++] = "Warning: pool[] is full; so, checks would not be enough hard...";
 285             }
 286         } else {
 287             // pool gets used for array index tests
 288             pool = new Object[3];
 289             poolSize = pool.length;
 290         }
 291 
 292         // Check ArithmeticException:
 293         try {
 294             int x, y, z;
 295             x = y = 0;
 296             z = x / y;
 297             log[messages++] = "Failure: ArithmeticException";
 298             exitCode = 2; // FAILED
 299         } catch (ArithmeticException ae) {
 300             if (TRACE_ON)
 301                 log[messages++] = "Success: ArithmeticException";
 302             if (exhaustHeap)
 303                 pool[index++] = ae;
 304         } catch (OutOfMemoryError oome) {
 305             if (WARN_ON)
 306                 log[messages++] = "Skipped: ArithmeticException";
 307             skipped++;
 308         }
 309 
 310         // Check ArrayIndexOutOfBoundsException:
 311         try {
 312             pool[poolSize] = pool[0];
 313             log[messages++] = "Failure: ArrayIndexOutOfBoundsException";
 314             exitCode = 2; // FAILED
 315         } catch (ArrayIndexOutOfBoundsException aioobe) {
 316             if (TRACE_ON)
 317                 log[messages++] = "Success: ArrayIndexOutOfBoundsException";
 318         } catch (OutOfMemoryError oome) {
 319             if (WARN_ON)
 320                 log[messages++] = "Skipped: ArrayIndexOutOfBoundsException";
 321             skipped++;
 322         }
 323 
 324         // Check ArrayStoreException:
 325         try {
 326             stringArray[0] = integerValue;
 327             log[messages++] = "Failure: ArrayStoreException";
 328             exitCode = 2; // FAILED
 329         } catch (ArrayStoreException ase) {
 330             if (TRACE_ON)
 331                 log[messages++] = "Success: ArrayStoreException";
 332         } catch (OutOfMemoryError oome) {
 333             if (WARN_ON)
 334                 log[messages++] = "Skipped: ArrayStoreException";
 335             skipped++;
 336         }
 337 
 338         // Check ClassCastException:
 339         try {
 340             trash = (Double) integerValue;
 341             log[messages++] = "Failure: ClassCastException";
 342             exitCode = 2; // FAILED
 343         } catch (ClassCastException cce) {
 344             if (TRACE_ON)
 345                 log[messages++] = "Success: ClassCastException";
 346             if (exhaustHeap)
 347                 pool[index++] = cce;
 348         } catch (OutOfMemoryError oome) {
 349             if (WARN_ON)
 350                 log[messages++] = "Skipped: ClassCastException";
 351             skipped++;
 352         }
 353 
 354         // Check CloneNotSupportedException:
 355         try {
 356             trash = abra.clone();    // illegal - should fail
 357 //          trash = cadabra.clone(); //   legal - should pass
 358             log[messages++] = "Failure: CloneNotSupportedException";
 359             exitCode = 2; // FAILED
 360         } catch (CloneNotSupportedException cnse) {
 361             if (TRACE_ON)
 362                 log[messages++] = "Success: CloneNotSupportedException";
 363         } catch (OutOfMemoryError oome) {
 364             if (WARN_ON)
 365                 log[messages++] = "Skipped: CloneNotSupportedException";
 366             skipped++;
 367         }
 368 
 369         // Check IllegalAccessException (positive):
 370         try {
 371             int junkIt = abraIntegerField.getInt(null); //   legal - should pass
 372 //          int junkIt = abraPrivateField.getInt(null); // illegal - should fail
 373             if (TRACE_ON)
 374                 log[messages++] = "Success: IllegalAccessException (positive)";
 375         } catch (IllegalAccessException iae) {
 376             log[messages++] = "Failure: IllegalAccessException (positive)";
 377             exitCode = 2;
 378         } catch (OutOfMemoryError oome) {
 379             if (WARN_ON)
 380                 log[messages++] = "Skipped: IllegalAccessException (positive)";
 381             skipped++;
 382         }
 383 
 384         // Check IllegalAccessException (negative):
 385         try {
 386 //          int junkIt = abraIntegerField.getInt(null); //   legal - should pass
 387             int junkIt = abraPrivateField.getInt(null); // illegal - should fail
 388             log[messages++] = "Failure: IllegalAccessException (negative)";
 389             exitCode = 2; // FAILED
 390         } catch (IllegalAccessException iae) {
 391             if (TRACE_ON)
 392                 log[messages++] = "Success: IllegalAccessException (negative)";
 393         } catch (OutOfMemoryError oome) {
 394             if (WARN_ON)
 395                 log[messages++] = "Skipped: IllegalAccessException (negative)";
 396             skipped++;
 397         }
 398 
 399         // Check IllegalArgumentException (positive):
 400         try {
 401             int junkIt = abraIntegerField.getInt(null); //   legal - should pass
 402 //          int junkIt = abraBooleanField.getInt(null); // illegal - should fail
 403             if (TRACE_ON)
 404                 log[messages++] = "Success: IllegalArgumentException (positive)";
 405         } catch (IllegalAccessException iae) {
 406             log[messages++] =
 407                     "Failure: IllegalArgumentException (positive) incorrectly thrown IllegalAccessException";
 408             exitCode = 2;
 409         } catch (IllegalArgumentException iae) {
 410             log[messages++] = "Failure: IllegalArgumentException (positive)";
 411             exitCode = 2;
 412         } catch (OutOfMemoryError oome) {
 413             if (WARN_ON)
 414                 log[messages++] = "Skipped: IllegalArgumentException (positive)";
 415             skipped++;
 416         }
 417 
 418         // Check IllegalArgumentException (negative):
 419         try {
 420 //          int junkIt = abraIntegerField.getInt(null); //   legal - should pass
 421             int junkIt = abraBooleanField.getInt(null); // illegal - should fail
 422             log[messages++] = "Failure: IllegalArgumentException (negative)";
 423             exitCode = 2; // FAILED
 424         } catch (IllegalAccessException iae) {
 425             log[messages++] =
 426                     "Failure: IllegalArgumentException (negative) incorrectly thrown IllegalAccessException";
 427             exitCode = 2;
 428         } catch (IllegalArgumentException iae) {
 429             if (TRACE_ON)
 430                 log[messages++] = "Success: IllegalArgumentException (negative)";
 431         } catch (OutOfMemoryError oome) {
 432             if (WARN_ON)
 433                 log[messages++] = "Skipped: IllegalArgumentException (negative)";
 434             skipped++;
 435         }
 436 
 437         // Check IllegalMonitorStateException (positive):
 438         try {
 439             synchronized (cadabra) {
 440                 cadabra.notifyAll();    //   legal - should pass
 441             }
 442 //          cadabra.notifyAll();        // illegal - should fail
 443             if (TRACE_ON)
 444                 log[messages++] = "Success: IllegalMonitorStateException (positive)";
 445         } catch (IllegalMonitorStateException imse) {
 446             log[messages++] = "Failure: IllegalMonitorStateException (positive)";
 447             exitCode = 2;
 448         } catch (OutOfMemoryError oome) {
 449             if (WARN_ON)
 450                 log[messages++] = "Skipped: IllegalMonitorStateException (positive)";
 451             skipped++;
 452         }
 453 
 454         // Check IllegalMonitorStateException (negative):
 455         try {
 456 //          synchronized (cadabra) {
 457 //              cadabra.notifyAll();    //   legal - should pass
 458 //          }
 459             cadabra.notifyAll();        // illegal - should fail
 460             log[messages++] = "Failure: IllegalMonitorStateException (negative)";
 461             exitCode = 2;
 462         } catch (IllegalMonitorStateException imse) {
 463             if (TRACE_ON)
 464                 log[messages++] = "Success: IllegalMonitorStateException (negative)";
 465         } catch (OutOfMemoryError oome) {
 466             if (WARN_ON)
 467                 log[messages++] = "Skipped: IllegalMonitorStateException (negative)";
 468             skipped++;
 469         }
 470 
 471         return exitCode;
 472     }
 473 
 474     /**
 475      * Re-call to <code>run(args,out)</code>, and return JCK-like exit status.
 476      * (The stream <code>out</code> is assigned to <code>System.out</code> here.)
 477      *
 478      * @see #run(String[], PrintStream)
 479      */
 480     public static void main(String args[]) {
 481         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
 482             // Last try. If there is some exception outside the code, test should end correctly
 483             @Override
 484             public void uncaughtException(Thread t, Throwable e) {
 485                 try {
 486                     pool = null;
 487                     log = null;
 488                     System.gc();
 489                     if (e instanceof OutOfMemoryError) {
 490                         try {
 491                             System.out.println("OOME : Test Skipped");
 492                             System.exit(0);
 493                         } catch (Throwable ignore) {
 494                         } // No code in the handler can provoke correct exceptions.
 495                     } else {
 496                         e.printStackTrace();
 497                         if (e instanceof RuntimeException)
 498                             throw (RuntimeException) e;
 499                         else if (e instanceof Error)
 500                             throw (Error) e;
 501                         else
 502                             throw new Error("Unexpected checked exception", e);
 503                     }
 504                 } catch (OutOfMemoryError oome) {
 505                 }
 506             }
 507         });
 508         int exitCode = run(args, System.out);
 509         System.exit(exitCode + 95);
 510         // JCK-like exit status.
 511     }
 512 
 513     /**
 514      * This class should be used to check <code>CloneNotSupportedException</code>,
 515      * <code>IllegalAccessException</code>, and <code>IllegalArgumentException</code>.
 516      * The class extends <code>except004</code> in order that its (protected)
 517      * method <code>clone()</code> be available from <code>except004</code>.
 518      */
 519     private static class Abra extends except004 {
 520         /**
 521          * Will try to incorrectly find this class as <code>Cadabra</code>
 522          * instead of <code>Abra$Cadabra</code>.
 523          */
 524         public static class Cadabra implements Cloneable {
 525         }
 526 
 527         /**
 528          * Will try to incorrectly access to this field from outside this class.
 529          */
 530         private static final int DONT_TOUCH_ME = 666;
 531         /**
 532          * Will try to incorrectly access to this field from outside this class.
 533          */
 534         public static final int MAIN_CYR_NUMBER = 47;
 535         /**
 536          * Will try to get this field like <code>int<code> zero.
 537          */
 538         public static final boolean NOT_AN_INTEGER = false;
 539 
 540         /**
 541          * Will try to correctly instantiate <code>Abra.Cadabra</code>,
 542          * not <code>Abra</code>.
 543          */
 544         private Abra() {
 545         }
 546 
 547         /**
 548          * Yet another constructor, which is <code>public</code>.
 549          */
 550         public Abra(String nothingSpecial) {
 551         }
 552     }
 553 }