8267118: OutOfMemoryError cannot be caught as a Throwable
Co-authored-by: Ioi Lam <iklam@openjdk.org> Reviewed-by: coleenp
This commit is contained in:
parent
de6472c441
commit
71425ddfb4
@ -1890,6 +1890,12 @@ void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_da
|
||||
catch_type_index, cp, CHECK_VERIFY(this));
|
||||
VerificationType throwable =
|
||||
VerificationType::reference_type(vmSymbols::java_lang_Throwable());
|
||||
// If the catch type is Throwable pre-resolve it now as the assignable check won't
|
||||
// do that, and we need to avoid a runtime resolution in case we are trying to
|
||||
// catch OutOfMemoryError.
|
||||
if (cp->klass_name_at(catch_type_index) == vmSymbols::java_lang_Throwable()) {
|
||||
cp->klass_at(catch_type_index, CHECK);
|
||||
}
|
||||
bool is_subclass = throwable.is_assignable_from(
|
||||
catch_type, this, false, CHECK_VERIFY(this));
|
||||
if (!is_subclass) {
|
||||
|
@ -226,6 +226,11 @@ void Method::print_external_name(outputStream *os, Klass* klass, Symbol* method_
|
||||
}
|
||||
|
||||
int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_klass, int throw_bci, TRAPS) {
|
||||
if (log_is_enabled(Debug, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_debug(exceptions)("Looking for catch handler for exception of type \"%s\" in method \"%s\"",
|
||||
ex_klass == NULL ? "NULL" : ex_klass->external_name(), mh->name()->as_C_string());
|
||||
}
|
||||
// exception table holds quadruple entries of the form (beg_bci, end_bci, handler_bci, klass_index)
|
||||
// access exception table
|
||||
ExceptionTable table(mh());
|
||||
@ -238,27 +243,67 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla
|
||||
int beg_bci = table.start_pc(i);
|
||||
int end_bci = table.end_pc(i);
|
||||
assert(beg_bci <= end_bci, "inconsistent exception table");
|
||||
log_debug(exceptions)(" - checking exception table entry for BCI %d to %d",
|
||||
beg_bci, end_bci);
|
||||
|
||||
if (beg_bci <= throw_bci && throw_bci < end_bci) {
|
||||
// exception handler bci range covers throw_bci => investigate further
|
||||
log_debug(exceptions)(" - entry covers throw point BCI %d", throw_bci);
|
||||
|
||||
int handler_bci = table.handler_pc(i);
|
||||
int klass_index = table.catch_type_index(i);
|
||||
if (klass_index == 0) {
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_info(exceptions)("Found catch-all handler for exception of type \"%s\" in method \"%s\" at BCI: %d",
|
||||
ex_klass == NULL ? "NULL" : ex_klass->external_name(), mh->name()->as_C_string(), handler_bci);
|
||||
}
|
||||
return handler_bci;
|
||||
} else if (ex_klass == NULL) {
|
||||
// Is this even possible?
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_info(exceptions)("NULL exception class is implicitly caught by handler in method \"%s\" at BCI: %d",
|
||||
mh()->name()->as_C_string(), handler_bci);
|
||||
}
|
||||
return handler_bci;
|
||||
} else {
|
||||
if (log_is_enabled(Debug, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_debug(exceptions)(" - resolving catch type \"%s\"",
|
||||
pool->klass_name_at(klass_index)->as_C_string());
|
||||
}
|
||||
// we know the exception class => get the constraint class
|
||||
// this may require loading of the constraint class; if verification
|
||||
// fails or some other exception occurs, return handler_bci
|
||||
Klass* k = pool->klass_at(klass_index, CHECK_(handler_bci));
|
||||
Klass* k = pool->klass_at(klass_index, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (log_is_enabled(Debug, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_debug(exceptions)(" - exception \"%s\" occurred resolving catch type",
|
||||
PENDING_EXCEPTION->klass()->external_name());
|
||||
}
|
||||
return handler_bci;
|
||||
}
|
||||
assert(k != NULL, "klass not loaded");
|
||||
if (ex_klass->is_subtype_of(k)) {
|
||||
if (log_is_enabled(Info, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_info(exceptions)("Found matching handler for exception of type \"%s\" in method \"%s\" at BCI: %d",
|
||||
ex_klass == NULL ? "NULL" : ex_klass->external_name(), mh->name()->as_C_string(), handler_bci);
|
||||
}
|
||||
return handler_bci;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (log_is_enabled(Debug, exceptions)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_debug(exceptions)("No catch handler found for exception of type \"%s\" in method \"%s\"",
|
||||
ex_klass->external_name(), mh->name()->as_C_string());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* @bug 8267118
|
||||
* @summary Test catching Throwable doesn't trigger OOME
|
||||
* @library /test/lib
|
||||
* @run driver TestCatchThrowableOOM
|
||||
*/
|
||||
|
||||
import java.util.HashMap;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class TestCatchThrowableOOM {
|
||||
|
||||
private static String[] expected = new String[] {
|
||||
"Test starting ...",
|
||||
"Test complete",
|
||||
"Exception <a 'java/lang/OutOfMemoryError'", // from logging
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xmx64m",
|
||||
"-Xlog:exceptions=trace",
|
||||
|
||||
"TestCatchThrowableOOM$OOM");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldHaveExitValue(0);
|
||||
for (String msg : expected) {
|
||||
output.shouldContain(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static class OOM {
|
||||
private static HashMap<Object, Object> store = new HashMap<>();
|
||||
public static void main(String[] args) {
|
||||
System.out.println(expected[0]);
|
||||
try {
|
||||
// Keep adding entries until we throw OOME
|
||||
while (true) {
|
||||
Object o = new Byte[100 * 1024];
|
||||
store.put(o, o);
|
||||
}
|
||||
} catch (Throwable oome) {
|
||||
store = null;
|
||||
System.gc(); // Just for good measure
|
||||
System.out.println(expected[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user