8075118: JVM stuck in infinite loop during verification
Summary: keep a list of handlers to prevent the same handler from being scanned repeatedly.
Reviewed-by: dlong, dholmes
--- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Mar 18 17:45:47 2015 -0400
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Thu Mar 19 08:55:50 2015 -0400
@@ -2236,14 +2236,20 @@
}
// Look at the method's handlers. If the bci is in the handler's try block
-// then check if the handler_pc is already on the stack. If not, push it.
+// then check if the handler_pc is already on the stack. If not, push it
+// unless the handler has already been scanned.
void ClassVerifier::push_handlers(ExceptionTable* exhandlers,
+ GrowableArray<u4>* handler_list,
GrowableArray<u4>* handler_stack,
u4 bci) {
int exlength = exhandlers->length();
for(int x = 0; x < exlength; x++) {
if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) {
- handler_stack->append_if_missing(exhandlers->handler_pc(x));
+ u4 exhandler_pc = exhandlers->handler_pc(x);
+ if (!handler_list->contains(exhandler_pc)) {
+ handler_stack->append_if_missing(exhandler_pc);
+ handler_list->append(exhandler_pc);
+ }
}
}
}
@@ -2261,6 +2267,10 @@
GrowableArray<u4>* bci_stack = new GrowableArray<u4>(30);
// Create stack for handlers for try blocks containing this handler.
GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30);
+ // Create list of handlers that have been pushed onto the handler_stack
+ // so that handlers embedded inside of their own TRY blocks only get
+ // scanned once.
+ GrowableArray<u4>* handler_list = new GrowableArray<u4>(30);
// Create list of visited branch opcodes (goto* and if*).
GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30);
ExceptionTable exhandlers(_method());
@@ -2279,7 +2289,7 @@
// If the bytecode is in a TRY block, push its handlers so they
// will get parsed.
- push_handlers(&exhandlers, handler_stack, bci);
+ push_handlers(&exhandlers, handler_list, handler_stack, bci);
switch (opcode) {
case Bytecodes::_if_icmpeq:
--- a/hotspot/src/share/vm/classfile/verifier.hpp Wed Mar 18 17:45:47 2015 -0400
+++ b/hotspot/src/share/vm/classfile/verifier.hpp Thu Mar 19 08:55:50 2015 -0400
@@ -305,9 +305,10 @@
bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table,
TRAPS);
- // Used by ends_in_athrow() to push all handlers that contain bci onto
- // the handler_stack, if the handler is not already on the stack.
+ // Used by ends_in_athrow() to push all handlers that contain bci onto the
+ // handler_stack, if the handler has not already been pushed on the stack.
void push_handlers(ExceptionTable* exhandlers,
+ GrowableArray<u4>* handler_list,
GrowableArray<u4>* handler_stack,
u4 bci);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/handlerInTry/HandlerInTry.jasm Thu Mar 19 08:55:50 2015 -0400
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/*
+ * HandlerInTry contains a try block in a ctor whose handler is inside
+ * the same try block. The try block starts at line 74 (try t2;), ends at
+ * line 106 (endtry t2;), but its handler starts at line 101 (catch t2 #0;).
+ */
+super public class HandlerInTry
+ version 51:0
+{
+
+public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;";
+
+public Method "<init>":"(Ljava/lang/Object;)V"
+ stack 5 locals 5
+{
+ invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;";
+ checkcast class java/lang/Object;
+ astore_2;
+ aload_2;
+ invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z";
+ ifeq L21;
+ aload_0;
+ aload_1;
+ aload_2;
+ invokespecial Method "<init>":"(Ljava/lang/Object;Ljava/lang/Object;)V";
+ return;
+ L21: stack_frame_type append;
+ locals_map class java/lang/Object;
+ aload_2;
+ getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;";
+ invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
+ astore_2;
+ aload_2;
+ iconst_1;
+ pop;
+ aload_2;
+ invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V";
+ try t0, t1;
+ aload_0;
+ aload_1;
+ aload_2;
+ invokespecial Method "<init>":"(Ljava/lang/Object;Ljava/lang/Object;)V";
+ aload_2;
+ pop;
+ aconst_null;
+ astore_2;
+ endtry t0, t1;
+ invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V";
+ pop;
+ goto L107;
+ catch t0 java/lang/Throwable;
+ try t2;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ astore_3;
+ aload_2;
+ pop;
+ aload_3;
+ instanceof class ControlFlowError;
+ ifeq L82;
+ new class java/lang/NullPointerException;
+ dup;
+ invokespecial Method java/lang/NullPointerException."<init>":"()V";
+ athrow;
+ L82: stack_frame_type append;
+ locals_map class java/lang/Throwable;
+ aload_3;
+ instanceof class java/lang/Error;
+ ifeq L94;
+ aload_3;
+ checkcast class java/lang/Error;
+ athrow;
+ L94: stack_frame_type same;
+ aload_3;
+ checkcast class java/lang/Exception;
+ athrow;
+ catch t1 #0;
+ catch t2 #0;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ astore 4;
+ endtry t2;
+ invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V";
+ aload 4;
+ athrow;
+ L107: stack_frame_type full;
+ locals_map class HandlerInTry, class java/lang/Object, null;
+ return;
+}
+
+} // end Class HandlerInTry
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/handlerInTry/IsolatedHandlerInTry.jasm Thu Mar 19 08:55:50 2015 -0400
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/*
+ * IsolatedHandlerInTry contains a try block in a ctor whose handler is inside
+ * the same try block but the handler can only be reached if an exception
+ * occurs. The handler does a return. So, a VerifyException should be thrown.
+ * The try block starts at line 77 (try t2;) and ends at line 113 (endtry t2;).
+ * Its handler starts at line 107 (catch t2 #0;). The handler can only be reached
+ * by exception because of the athrow at line 106.
+ */
+super public class IsolatedHandlerInTry
+ version 51:0
+{
+
+public static final synthetic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;";
+
+public Method "<init>":"(Ljava/lang/Object;)V"
+ stack 5 locals 5
+{
+ invokestatic Method ThreadLocalTransaction.getThreadLocalTransaction:"()Ljava/lang/Object;";
+ checkcast class java/lang/Object;
+ astore_2;
+ aload_2;
+ invokestatic Method TransactionLogicDonor.isActiveTransaction:"(Ljava/lang/Object;)Z";
+ ifeq L21;
+ aload_0;
+ aload_1;
+ aload_2;
+ invokespecial Method "<init>":"(Ljava/lang/Object;Ljava/lang/Object;)V";
+ return;
+ L21: stack_frame_type append;
+ locals_map class java/lang/Object;
+ aload_2;
+ getstatic Field ___transactionFactory_2002349702336125:"Ljava/lang/Object;";
+ invokestatic Method TransactionLogicDonor.createTransaction:"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
+ astore_2;
+ aload_2;
+ iconst_1;
+ pop;
+ aload_2;
+ invokestatic Method ThreadLocalTransaction.setThreadLocalTransaction:"(Ljava/lang/Object;)V";
+ try t0, t1;
+ aload_0;
+ aload_1;
+ aload_2;
+ invokespecial Method "<init>":"(Ljava/lang/Object;Ljava/lang/Object;)V";
+ aload_2;
+ pop;
+ aconst_null;
+ astore_2;
+ endtry t0, t1;
+ invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V";
+ pop;
+ goto L107;
+ catch t0 java/lang/Throwable;
+ try t2;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ astore_3;
+ aload_2;
+ pop;
+ aload_3;
+ instanceof class ControlFlowError;
+ ifeq L82;
+ new class java/lang/NullPointerException;
+ dup;
+ invokespecial Method java/lang/NullPointerException."<init>":"()V";
+ athrow;
+ L82: stack_frame_type append;
+ locals_map class java/lang/Throwable;
+ aload_3;
+ instanceof class java/lang/Error;
+ ifeq L94;
+ aload_3;
+ checkcast class java/lang/Error;
+ athrow;
+ L94: stack_frame_type same;
+ aload_3;
+ checkcast class java/lang/Exception;
+ catch t1 #0;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ athrow;
+ catch t2 #0;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ astore 4;
+ return;
+ endtry t2;
+ stack_frame_type full;
+ locals_map bogus, class java/lang/Object, class java/lang/Object, class java/lang/Object;
+ stack_map class java/lang/Throwable;
+ invokestatic Method ThreadLocalTransaction.clearThreadLocalTransaction:"()V";
+ athrow;
+ L107: stack_frame_type full;
+ locals_map class IsolatedHandlerInTry, class java/lang/Object, null;
+ return;
+}
+
+} // end Class IsolatedHandlerInTry
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/handlerInTry/LoadHandlerInTry.java Thu Mar 19 08:55:50 2015 -0400
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 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 8075118
+ * @summary Allow a ctor to call super() from a switch bytecode.
+ * @compile HandlerInTry.jasm
+ * @compile IsolatedHandlerInTry.jasm
+ * @run main/othervm -Xverify:all LoadHandlerInTry
+ */
+
+/*
+ * This test has two cases:
+ *
+ * 1. class HandlerInTry: Class HandlerInTry contains a TRY block in a
+ * constructor whose handler is inside the same TRY block. The last
+ * few bytecodes and exception table look like this:
+ *
+ * ...
+ * 87: athrow
+ * 88: astore 4
+ * 90: invokestatic #9
+ * 93: aload 4
+ * 95: athrow
+ * 96: return
+ * Exception table:
+ * from to target type
+ * 36 46 53 Class java/lang/Throwable
+ * 36 46 88 any
+ * 53 90 88 any
+ *
+ * Note that the target for the third handler in the Exception table is
+ * inside its TRY block.
+ * Without the fix for bug JDK-8075118, this test will time out.
+ *
+ *
+ * 2. class IsolatedHandlerInTry: Class IsolatedHandlerInTry also contains
+ * a TRY block in a constructoer whose handler is inside its TRY block.
+ * But the handler is only reachable if an exception is thrown. The
+ * handler's bytecodes will not get parsed as part of parsing the TRY
+ * block. They will only get parsed as a handler for the TRY block.
+ * Since the isolated handler does a 'return', a VerifyError exception
+ * should get thrown.
+ */
+
+public class LoadHandlerInTry {
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("Regression test for bug 8075118");
+ try {
+ Class newClass = Class.forName("HandlerInTry");
+ } catch (Exception e) {
+ System.out.println("Failed: Exception was thrown: " + e.toString());
+ throw e;
+ }
+
+ try {
+ Class newClass = Class.forName("IsolatedHandlerInTry");
+ throw new RuntimeException(
+ "Failed to throw VerifyError for IsolatedHandlerInTry");
+ } catch (java.lang.VerifyError e) {
+ System.out.println("Passed: VerifyError exception was thrown");
+ }
+ }
+}