/* * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @key stress * * @summary converted from VM testbase nsk/stress/except/except004. * VM testbase keywords: [stress, diehard, slow, nonconcurrent, quick] * VM testbase readme: * DESCRIPTION * This checks if various exceptions are thrown (and caught) correctly * when there apparently are no free space in the heap to allocate new * Throwable instance. * The test tries to occupy all of memory available in the heap by allocating * lots of new Object() instances. Instances of the type Object are the smallest * objects, so they apparently should occupy most fine-grained fragments in the * heap and leave no free space for new Throwable instance. After that, the test * provokes various exceptions (e.g.: by executing integer division by 0 and so * on), and checks if appropriate exceptions are thrown. * COMMENTS * The test needs a lot of memory to start up, so it should not run under older * JDK 1.1.x release due to its poorer heap utilization. Also, some checks are * skipped when testing classic VM, because OutOfMemoryError is correctly thrown * instead of target exception. * When the test is being self-initiating (i.e.: eating heap), memory occupation * is terminated if memory allocation slows down crucially. This is a workaround * intended to avoid the HotSpot bug: * #4248801 (P1/S5) slow memory allocation when heap is almost exhausted * There is also a workaround involved to avoid the following bugs known * for HotSpot and for classic VM: * #4239841 (P1/S5) 1.1: poor garbage collector performance (HotSpot bug) * #4245060 (P4/S5) poor garbage collector performance (Classic VM bug) * However, printing of the test's error messages, warnings, and of execution * trace fails under JDK 1.2 for Win32 even so. If the test fails due to this * problem, exit status 96 is returned instead of 97. * JDK 1.3 classic VM for Sparc may crash (core dump) due to the known bug: * #4245057 (P2/S3) VM crashes when heap is exhausted * * @run main/othervm -Xms50M -Xmx200M -XX:-UseGCOverheadLimit nsk.stress.except.except004 */ package nsk.stress.except; import java.io.PrintStream; import java.lang.reflect.Field; /** * This checks if various exceptions are thrown (and caught) correctly * when there apparently are no free space in the heap to allocate new * Throwable instance. *

*

The test tries to occupy all of memory available in the heap by * allocating lots of new Object() instances. Instances of the * type Object are the smallest objects, so they apparently should * occupy most fine-grained fragments in the heap and leave no free space for * new Throwable instance. After that, the test provokes various * exceptions (e.g.: by executing integer division by 0 and so on), and checks * if appropriate exceptions are thrown. *

*

Note, that memory occupation is terminated if memory allocation slows * down crucially. This is a workaround intended to avoid the HotSpot bug: *
   * #4248801 (P1/S5) slow memory allocation when heap is almost exhausted *

*

There is also a workaround involved to avoid the following bugs known * for HotSpot and for classic VM: *
   * #4239841 (P1/S5) 1.1: poor garbage collector performance *
   * #4245060 (P4/S5) poor garbage collector performance *
However, printing of the test's error messages, warnings, and of * execution trace may fail even so. If the test fails due to poor GC * performance, exit status 96 is returned instead of 97. *

*

Also note, that the test needs a lot of memory to start up, so it should * not run under older JDK 1.1.x release due to its poor heap utilization. */ public class except004 { /** * Either allow or supress printing of execution trace. */ private static boolean TRACE_ON = false; /** * Either allow or supress printing of warning messages. */ private static final boolean WARN_ON = true; /* * Storage for a lot of tiny objects * "static volatile" keywords are for preventing heap optimization */ private static volatile Object pool[] = null; /** * Temporary log for error messages, warnings and/or execution trace. * * @see #messages */ private static String log[] = new String[1000]; // up to 1000 messages /** * How many messages were submitted to the log. * * @see #log */ private static int messages = 0; /** * Re-call to the method run(out) (ignore args[]), * and print the test summary - either test passed of failed. */ public static int run(String args[], PrintStream out) { if (args.length > 0) { if (args[0].toLowerCase().startsWith("-v")) TRACE_ON = true; } int exitCode; try { exitCode = run(out); } finally { // ensure we have free memory for exception processing pool = null; System.gc(); } if (TRACE_ON) out.println("Test completed."); // Print the log[] and the test summary: try { for (int i = 0; i < messages; i++) out.println(log[i]); if (exitCode == 0) { if (TRACE_ON) out.println("Test passed."); } else out.println("Test failed."); } catch (OutOfMemoryError oome) { // Poor performance of garbage collector: exitCode = 1; } return exitCode; } /** * Allocate as much Object instances as possible to bring JVM * into stress, and then check if exceptions are correctly thrown accordingly * to various situations like integer division by 0, etc. */ private static int run(PrintStream out) { out.println("# While printing this message, JVM seems to initiate the output"); out.println("# stream, so that it will not need more memory to print later,"); out.println("# when the heap would fail to provide more memory."); out.println("# "); out.println("# Note, that the test maintains especial static log[] field in"); out.println("# order to avoid printing when the heap seems exhausted."); out.println("# Nevertheless, printing could cause OutOfMemoryError even"); out.println("# after all the memory allocated by the test is released."); out.println("# "); out.println("# That problem is caused by the known JDK/HotSpot bugs:"); out.println("# 4239841 (P1/S5) 1.1: poor garbage collector performance"); out.println("# 4245060 (P4/S5) poor garbage collector performance"); out.println("# "); out.println("# This message is just intended to work-around that problem."); out.println("# If printing should fail even so, the test will return the"); out.println("# exit status 96 instead of 97 to indicate the problem."); // run all tests normally to ensure all needed classes are loaded and // initialized before the heap is exhausted - else we may trigger OOME // in unexpected places. try { if (TRACE_ON) out.println("Running without heap exhaustion"); runTests(out, false); } catch (Throwable unexpected) { out.println("Test pre-initialisation failed: " + unexpected); return 2; } if (TRACE_ON) out.println("Running with heap exhaustion"); return runTests(out, true); } private static int runTests(PrintStream out, boolean exhaustHeap) { // reset message index messages = 0; // Prepare some items, which will be used by the test: Object stringArray[] = new String[1]; Object integerValue = new Integer(0); Object doubleValue = new Double(0); Object trash = null; Field abraIntegerField; Field abraBooleanField; Field extPrivateField; try { abraIntegerField = Abra.class.getDeclaredField("MAIN_CYR_NUMBER"); abraBooleanField = Abra.class.getDeclaredField("NOT_AN_INTEGER"); extPrivateField = Ext.class.getDeclaredField("DONT_TOUCH_ME"); } catch (NoSuchFieldException nsfe) { out.println("Test initialisation failed: field not found: " + nsfe.getMessage()); return 2; } Abra abra = new Abra("via public constructor"); Abra.Cadabra cadabra = new Abra.Cadabra(); // Sum up exit code: int exitCode = 0; // apparently PASSED int skipped = 0; // some checks may correctly suffer OutOfMemoryError int poolSize = 0; int index = 0; if (exhaustHeap) { pool = null; // Allocate repository for lots of tiny objects: for (int size = 1 << 30; size > 0 && pool == null; size >>= 1) { try { pool = new Object[size]; } catch (OutOfMemoryError oome) { } } if (pool == null) throw new Error("HS bug: cannot allocate new Object[1]"); poolSize = pool.length; index = 0; // Sum up time spent, when it was hard for JVM to allocate next object // (i.e.: when JVM has spent more than 1 second to allocate new object): double totalDelay = 0; long timeMark = System.currentTimeMillis(); try { for (; index < poolSize; index++) { //------------------------- pool[index] = new Object(); long nextTimeMark = System.currentTimeMillis(); long elapsed = nextTimeMark - timeMark; timeMark = nextTimeMark; //---------------------- if (elapsed > 1000) { double seconds = elapsed / 1000.0; if (TRACE_ON) out.println( "pool[" + index + "]=new Object(); // elapsed " + seconds + "s"); totalDelay += seconds; if (totalDelay > 60) { if (TRACE_ON) out.println( "Memory allocation became slow; so, heap seems exhausted."); break; } } } } catch (OutOfMemoryError oome) { if (TRACE_ON) log[messages++] = "Heap seems exhausted - OutOfMemoryError thrown."; // Do not release any byte once allocated: pool[index++] = oome; } if (index > poolSize - 1000) { if (WARN_ON) log[messages++] = "Warning: pool[] is full; so, checks would not be enough hard..."; } } else { // pool gets used for array index tests pool = new Object[3]; poolSize = pool.length; } // Check ArithmeticException: try { int x, y, z; x = y = 0; z = x / y; log[messages++] = "Failure: ArithmeticException"; exitCode = 2; // FAILED } catch (ArithmeticException ae) { if (TRACE_ON) log[messages++] = "Success: ArithmeticException"; if (exhaustHeap) pool[index++] = ae; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: ArithmeticException"; skipped++; } // Check ArrayIndexOutOfBoundsException: try { pool[poolSize] = pool[0]; log[messages++] = "Failure: ArrayIndexOutOfBoundsException"; exitCode = 2; // FAILED } catch (ArrayIndexOutOfBoundsException aioobe) { if (TRACE_ON) log[messages++] = "Success: ArrayIndexOutOfBoundsException"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: ArrayIndexOutOfBoundsException"; skipped++; } // Check ArrayStoreException: try { stringArray[0] = integerValue; log[messages++] = "Failure: ArrayStoreException"; exitCode = 2; // FAILED } catch (ArrayStoreException ase) { if (TRACE_ON) log[messages++] = "Success: ArrayStoreException"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: ArrayStoreException"; skipped++; } // Check ClassCastException: try { trash = (Double) integerValue; log[messages++] = "Failure: ClassCastException"; exitCode = 2; // FAILED } catch (ClassCastException cce) { if (TRACE_ON) log[messages++] = "Success: ClassCastException"; if (exhaustHeap) pool[index++] = cce; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: ClassCastException"; skipped++; } // Check CloneNotSupportedException: try { trash = abra.clone(); // illegal - should fail // trash = cadabra.clone(); // legal - should pass log[messages++] = "Failure: CloneNotSupportedException"; exitCode = 2; // FAILED } catch (CloneNotSupportedException cnse) { if (TRACE_ON) log[messages++] = "Success: CloneNotSupportedException"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: CloneNotSupportedException"; skipped++; } // Check IllegalAccessException (positive): try { int junkIt = abraIntegerField.getInt(null); // legal - should pass if (TRACE_ON) log[messages++] = "Success: IllegalAccessException (positive)"; } catch (IllegalAccessException iae) { log[messages++] = "Failure: IllegalAccessException (positive)"; exitCode = 2; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalAccessException (positive)"; skipped++; } // Check IllegalAccessException (negative): try { int junkIt = extPrivateField.getInt(null); // illegal - should fail log[messages++] = "Failure: IllegalAccessException (negative)"; exitCode = 2; // FAILED } catch (IllegalAccessException iae) { if (TRACE_ON) log[messages++] = "Success: IllegalAccessException (negative)"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalAccessException (negative)"; skipped++; } // Check IllegalArgumentException (positive): try { int junkIt = abraIntegerField.getInt(null); // legal - should pass // int junkIt = abraBooleanField.getInt(null); // illegal - should fail if (TRACE_ON) log[messages++] = "Success: IllegalArgumentException (positive)"; } catch (IllegalAccessException iae) { log[messages++] = "Failure: IllegalArgumentException (positive) incorrectly thrown IllegalAccessException"; exitCode = 2; } catch (IllegalArgumentException iae) { log[messages++] = "Failure: IllegalArgumentException (positive)"; exitCode = 2; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalArgumentException (positive)"; skipped++; } // Check IllegalArgumentException (negative): try { // int junkIt = abraIntegerField.getInt(null); // legal - should pass int junkIt = abraBooleanField.getInt(null); // illegal - should fail log[messages++] = "Failure: IllegalArgumentException (negative)"; exitCode = 2; // FAILED } catch (IllegalAccessException iae) { log[messages++] = "Failure: IllegalArgumentException (negative) incorrectly thrown IllegalAccessException"; exitCode = 2; } catch (IllegalArgumentException iae) { if (TRACE_ON) log[messages++] = "Success: IllegalArgumentException (negative)"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalArgumentException (negative)"; skipped++; } // Check IllegalMonitorStateException (positive): try { synchronized (cadabra) { cadabra.notifyAll(); // legal - should pass } // cadabra.notifyAll(); // illegal - should fail if (TRACE_ON) log[messages++] = "Success: IllegalMonitorStateException (positive)"; } catch (IllegalMonitorStateException imse) { log[messages++] = "Failure: IllegalMonitorStateException (positive)"; exitCode = 2; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalMonitorStateException (positive)"; skipped++; } // Check IllegalMonitorStateException (negative): try { // synchronized (cadabra) { // cadabra.notifyAll(); // legal - should pass // } cadabra.notifyAll(); // illegal - should fail log[messages++] = "Failure: IllegalMonitorStateException (negative)"; exitCode = 2; } catch (IllegalMonitorStateException imse) { if (TRACE_ON) log[messages++] = "Success: IllegalMonitorStateException (negative)"; } catch (OutOfMemoryError oome) { if (WARN_ON) log[messages++] = "Skipped: IllegalMonitorStateException (negative)"; skipped++; } return exitCode; } /** * Re-call to run(args,out), and return JCK-like exit status. * (The stream out is assigned to System.out here.) * * @see #run(String[], PrintStream) */ public static void main(String args[]) { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { // Last try. If there is some exception outside the code, test should end correctly @Override public void uncaughtException(Thread t, Throwable e) { try { pool = null; log = null; System.gc(); if (e instanceof OutOfMemoryError) { try { System.out.println("OOME : Test Skipped"); System.exit(0); } catch (Throwable ignore) { } // No code in the handler can provoke correct exceptions. } else { e.printStackTrace(); if (e instanceof RuntimeException) throw (RuntimeException) e; else if (e instanceof Error) throw (Error) e; else throw new Error("Unexpected checked exception", e); } } catch (OutOfMemoryError oome) { } } }); int exitCode = run(args, System.out); System.exit(exitCode + 95); // JCK-like exit status. } /** * This class should be used to check CloneNotSupportedException, * and IllegalArgumentException. * The class extends except004 in order that its (protected) * method clone() be available from except004. */ private static class Abra extends except004 { /** * Will try to incorrectly find this class as Cadabra * instead of Abra$Cadabra. */ public static class Cadabra implements Cloneable { } /** * Will try to incorrectly access to this field from outside this class. */ public static final int MAIN_CYR_NUMBER = 47; /** * Will try to get this field like int zero. */ public static final boolean NOT_AN_INTEGER = false; /** * Will try to correctly instantiate Abra.Cadabra, * not Abra. */ private Abra() { } /** * Yet another constructor, which is public. */ public Abra(String nothingSpecial) { } } } /* Package accessible class that has non-accessible private member */ class Ext { /** * Will try to incorrectly access to this field from outside this class. */ private static final int DONT_TOUCH_ME = 666; }