8035119: Fix exceptions to bytecode verification
Summary: Prevent ctor calls to super() and this() from avoidable code (try blocks, if stmts, etc.)
Reviewed-by: coleenp, acorn, mschoene
--- a/hotspot/src/share/vm/classfile/stackMapTable.cpp Wed May 07 19:21:52 2014 +0400
+++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp Mon Jul 14 12:45:14 2014 +0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, 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
@@ -134,6 +134,7 @@
}
// check if uninitialized objects exist on backward branches
check_new_object(frame, target, CHECK_VERIFY(frame->verifier()));
+ frame->verifier()->update_furthest_jump(target);
}
void StackMapTable::check_new_object(
--- a/hotspot/src/share/vm/classfile/verifier.cpp Wed May 07 19:21:52 2014 +0400
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Mon Jul 14 12:45:14 2014 +0400
@@ -633,6 +633,9 @@
bool no_control_flow = false; // Set to true when there is no direct control
// flow from current instruction to the next
// instruction in sequence
+
+ set_furthest_jump(0);
+
Bytecodes::Code opcode;
while (!bcs.is_last_bytecode()) {
// Check for recursive re-verification before each bytecode.
@@ -2248,6 +2251,29 @@
"Bad <init> method call");
return;
}
+
+ // Make sure that this call is not jumped over.
+ if (bci < furthest_jump()) {
+ verify_error(ErrorContext::bad_code(bci),
+ "Bad <init> method call from inside of a branch");
+ return;
+ }
+
+ // Make sure that this call is not done from within a TRY block because
+ // that can result in returning an incomplete object. Simply checking
+ // (bci >= start_pc) also ensures that this call is not done after a TRY
+ // block. That is also illegal because this call must be the first Java
+ // statement in the constructor.
+ ExceptionTable exhandlers(_method());
+ int exlength = exhandlers.length();
+ for(int i = 0; i < exlength; i++) {
+ if (bci >= exhandlers.start_pc(i)) {
+ verify_error(ErrorContext::bad_code(bci),
+ "Bad <init> method call from after the start of a try block");
+ return;
+ }
+ }
+
current_frame->initialize_object(type, current_type());
*this_uninit = true;
} else if (type.is_uninitialized()) {
--- a/hotspot/src/share/vm/classfile/verifier.hpp Wed May 07 19:21:52 2014 +0400
+++ b/hotspot/src/share/vm/classfile/verifier.hpp Mon Jul 14 12:45:14 2014 +0400
@@ -258,6 +258,9 @@
ErrorContext _error_context; // contains information about an error
+ // Used to detect illegal jumps over calls to super() nd this() in ctors.
+ int32_t _furthest_jump;
+
void verify_method(methodHandle method, TRAPS);
char* generate_code_data(methodHandle m, u4 code_length, TRAPS);
void verify_exception_handler_table(u4 code_length, char* code_data,
@@ -403,6 +406,20 @@
Symbol* create_temporary_symbol(const char *s, int length, TRAPS);
TypeOrigin ref_ctx(const char* str, TRAPS);
+
+ // Keep track of the furthest branch done in a method to make sure that
+ // there are no branches over calls to super() or this() from inside of
+ // a constructor.
+ int32_t furthest_jump() { return _furthest_jump; }
+
+ void set_furthest_jump(int32_t target) {
+ _furthest_jump = target;
+ }
+
+ void update_furthest_jump(int32_t target) {
+ if (target > _furthest_jump) _furthest_jump = target;
+ }
+
};
inline int ClassVerifier::change_sig_to_verificationType(