Jean Christophe Beyler 5639c70032 8213721: [Graal] Tests vmTestbase/nsk/stress/except/except* may be encountering SEGV during out-of-memory conditions
Add the exception handler only for the current thread

Reviewed-by: dholmes, sspitsyn, thartmann
2018-11-21 09:38:27 -08:00

292 lines
12 KiB
Java

/*
* 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/except001.
* VM testbase keywords: [stress, diehard, slow, nonconcurrent, quick]
* VM testbase readme:
* DESCRIPTION
* This checks if OutOfMemoryError exception is correctly enwrapped into
* InvocationTargetException when thrown inside a method invoked via
* reflection.
* The test tries to occupy all of memory available in the heap by
* allocating lots of new Object() instances. Instances of the "empty"
* type Object are the smallest objects, so they apparently should occupy
* most fine-grained fragments in the heap. Thus, there apparently should
* not remain any free space to incarnate new Throwable instance, and VM
* possibly could crash while trying to throw new OutOfMemoryError and
* enwrap it into new InvocationTargetException instance.
* By the way, the test checks time elapsed to allocate memory. Both
* classic VM and HotSpot seem to fall into poor performance of memory
* allocation when heap is almost over. E.g.: HotSpot 1.3-betaH may spend
* more than 1 minute to allocate next Object in this case (tested on
* Pentium-II, 350MHz, 128Mb RAM). To avoid this problem, the test enforce
* OutOfMemoryError if more then 5 minutes is spent to allocate "last bytes"
* of memory.
* COMMENTS
* HotSpot releases 1.0-fcsE (both Win32 and Sparc), and 1.3-betaH (Win32)
* fail on this test due to poor performance of memory allocation.
* #4248801 (P3/S5) slow memory allocation when heap is almost exhausted
* Despite this bug is treated fixed in HotSpot 1.0.1, it still does suffer
* slow memory allocation when running on PC having 64Mb or less of RAM.
* 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 may fail under JDK 1.2 for Win32 even so.
* HotSpot 2.0-devA (Win32) crashes due to the known HotSpot bug:
* #4239828 (P1/S4) 1.3c1: VM crashes when heap is exhausted
*
* @run main/othervm -Xms50M -Xmx200M nsk.stress.except.except001
*/
package nsk.stress.except;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* This checks if <code>OutOfMemoryError</code> exception is correctly
* enwrapped into <code>InvocationTargetException</code> when thrown inside
* a method invoked via reflection.
* <p>
* <p>The test tries to occupy all of memory available in the heap by
* allocating lots of new <code>Object()</code> instances. Instances of the
* ``empty'' type <code>Object</code> are the smallest objects, so they
* apparently should occupy most fine-grained fragments in the heap.
* Thus, there apparently should not remain any free space to incarnate new
* <code>Throwable</code> instance, and VM possibly could crash while trying
* to throw new <code>OutOfMemoryError</code> and enwrap it into new
* <code>InvocationTargetException</code> instance.
* <p>
* <p>By the way, the test checks time elapsed to allocate memory.
* Both classic VM and HotSpot seem to fall into poor performance of memory
* allocation when heap is almost over. E.g.: HotSpot 1.3-betaH may spend
* more than 1 minute to allocate next <code>Object</code> in this case
* (tested on Pentium-II, 350MHz, 128Mb RAM). To workaround this problem,
* the test enforces <code>OutOfMemoryError</code> if more then 5 minutes
* is spent to allocate ``last bytes'' of the memory.
*/
public class except001 {
/**
* This field allows or supresses printing with <code>display()</code>
* method.
*
* @see #display(Object)
* @see #complain(Object)
* @see #out
*/
private static boolean MODE_VERBOSE = true;
/*
* Storage for a lot of tiny objects
* "static volatile" keywords are for preventing heap optimization
*/
private static volatile Object pool[] = null;
/**
* Print execution trace if <code>MODE_VERBOSE</code> is <code>true</code>
* (optional).
*
* @see #MODE_VERBOSE
* @see #complain(Object)
* @see #out
*/
private static void display(Object message) {
if (MODE_VERBOSE)
out.println(message.toString());
out.flush();
}
/**
* Print error <code>message</code>.
*
* @see #display(Object)
* @see #out
*/
private static void complain(Object message) {
out.println("# " + message);
out.flush();
}
/**
* The log-stream assigned at runtime by the method
* <code>run(args,out)</code>.
*
* @see #display(Object)
* @see #complain(Object)
* @see #run(String[], PrintStream)
*/
private static PrintStream out;
/**
* Try to allocate lots of instances of the type <code>Object</code>.
* Such instances are most fine-grained, and thus they should occupy
* smallest fragments of free memory in the heap.
* <p>
* <p>By the way, break the test, if JVM has spent more than
* 5 minutes to allocate latest portions of memory.
*/
public static void raiseOutOfMemory() throws OutOfMemoryError {
try {
// Repository for objects, which should be allocated:
int index = 0;
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]");
// Sum up time spent, when it was hard to 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();
for (; index < pool.length; index++) {
//-------------------------
pool[index] = new Object();
long nextTimeMark = System.currentTimeMillis();
long elapsed = nextTimeMark - timeMark;
timeMark = nextTimeMark;
//----------------------
if (elapsed > 1000) {
double seconds = elapsed / 1000.0;
display(
"pool[" + index +
"]=new Object(); // elapsed " + seconds + "s");
totalDelay += seconds;
if (totalDelay > 300) {
complain(
"Memory allocation became slow: so heap seems exhausted.");
throw new OutOfMemoryError();
}
}
}
// This method should never return:
throw new Error("TEST_BUG: failed to provoke OutOfMemoryError");
} finally {
// Make sure there will be enough memory for next object allocation
pool = null;
}
}
/**
* Invoke the method <code>raiseOutOfMemory()</code> with reflection,
* and check if the exception it throws is just
* <code>OutOfMemoryError</code> enwrapped into
* <code>InvocationTargetException</code> instance.
* <p>
* <p>Before the test begins, <code>this.out</code> filed is assigned
* to the parameter <code>out</code>. Parameter <code>args[]</code>
* is ignored.
*
* @see #raiseOutOfMemory()
*/
public static int run(String args[], 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("# 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.");
if (args.length > 0) {
if (args[0].toLowerCase().startsWith("-v"))
MODE_VERBOSE = true;
}
except001.out = out;
Class testClass = except001.class;
try {
Method testMethod = testClass.getMethod("raiseOutOfMemory", new Class [0]);
Object junk = testMethod.invoke(null, new Object [0]);
} catch (InvocationTargetException ite) {
Throwable targetException = ite.getTargetException();
if (targetException instanceof OutOfMemoryError) {
display("OutOfMemoryError thrown as expected.");
display("Test passed.");
return 0;
}
complain("Unexpected InvocationTargetException: " + targetException);
complain("Test failed.");
return 2;
} catch (Exception exception) {
complain("Unexpected exception: " + exception);
complain("Test failed.");
return 2;
}
//
complain("The test has finished unexpectedly.");
complain("Test failed.");
return 2;
}
/**
* Re-call to <code>run(args,out)</code>, and return JCK-like exit status.
* (The stream <code>out</code> is assigned to <code>System.out</code> here.)
*
* @see #run(String[], PrintStream)
*/
public static void main(String args[]) {
Thread.currentThread().setUncaughtExceptionHandler(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;
System.gc();
if (e instanceof OutOfMemoryError) {
try {
System.out.println("OOME : Test Skipped");
System.exit(95);
} catch (Throwable ignore) {
} // No code in the handler can provoke correct exceptions.
} else {
e.printStackTrace();
throw (RuntimeException) e;
}
} catch (OutOfMemoryError oome) {
}
}
});
int exitCode = run(args, System.out);
System.exit(exitCode + 95);
// JCK-like exit status.
}
}