src/share/vm/classfile/verifier.cpp
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File
bug_8050485_2 Cdiff src/share/vm/classfile/verifier.cpp
src/share/vm/classfile/verifier.cpp
Print this page
*** 2217,2226 ****
--- 2217,2368 ----
}
default: ShouldNotReachHere();
}
}
+ // Return TRUE if all code paths in the bytecode interval end in athrow.
+ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset, u4 end_bc_offset) {
+ // Create bytecode stream.
+ RawBytecodeStream bcs(method());
+ bcs.set_interval(start_bc_offset, end_bc_offset);
+ u4 code_length = method()->code_size();
+ u4 target;
+ // Create stack for storing bytecode intervals for if*, goto*, and *switch.
+ GrowableArray<u4>* bci_stack = new GrowableArray<u4>(50);
+
+ while (true) {
+ if (bcs.is_last_bytecode()) {
+ if (bci_stack->is_empty()) {
+ return false;
+ } else {
+ // Pop a bytecode interval and scan that interval.
+ u4 end_offset = pop_bci_end_offset(bci_stack);
+ u4 start_offset = pop_bci_start_offset(bci_stack);
+ assert(end_offset >= start_offset, "Messed up bytecode offsets");
+ bcs.set_interval(start_offset, end_offset);
+ }
+ }
+ Bytecodes::Code opcode = bcs.raw_next();
+ u4 bci = bcs.bci();
+
+ switch (opcode) {
+ case Bytecodes::_if_icmpeq:
+ case Bytecodes::_if_icmpne:
+ case Bytecodes::_if_icmplt:
+ case Bytecodes::_if_icmpge:
+ case Bytecodes::_if_icmpgt:
+ case Bytecodes::_if_icmple:
+ case Bytecodes::_ifeq:
+ case Bytecodes::_ifne:
+ case Bytecodes::_iflt:
+ case Bytecodes::_ifge:
+ case Bytecodes::_ifgt:
+ case Bytecodes::_ifle:
+ case Bytecodes::_if_acmpeq:
+ case Bytecodes::_if_acmpne:
+ case Bytecodes::_ifnull:
+ case Bytecodes::_ifnonnull:
+ target = bcs.dest();
+ if (target > bci) { // forward branch
+ if (target >= code_length) return false;
+ // Push the branch target interval onto the stack.
+ push_bci_offsets(bci_stack, target, bcs.end_bci());
+ // then, scan bytecodes up to the target.
+ bcs.set_interval(bcs.next_bci(), target);
+
+ } else { // backward branch
+ // Push the interval following the backward branch onto the stack.
+ push_bci_offsets(bci_stack, bcs.next_bci(), bcs.end_bci());
+ // Check bytecodes between the branch target and the current offset.
+ bcs.set_interval(target, bci);
+ }
+ break;
+
+ case Bytecodes::_goto:
+ case Bytecodes::_goto_w:
+ target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
+ if (target > bci) { // forward branch
+ if (target >= code_length) return false;
+ bcs.set_interval(target, code_length);
+
+ } else { // backward branch
+ // Push the interval following the backward branch onto the stack.
+ push_bci_offsets(bci_stack, bcs.next_bci(), bcs.end_bci());
+ // Check bytecodes between the branch target and the current offset.
+ bcs.set_interval(target, bci);
+ }
+ break;
+
+ // Check that all switch alternatives end in 'athrow' bytecodes. Since it
+ // is difficult to determine where each switch alternative ends, parse
+ // each switch alternative until either hit a 'return', 'athrow', or reach
+ // the end of the method's bytecodes. This is gross but should be okay
+ // because:
+ // 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit
+ // constructor invocations should be rare.
+ // 2. if each switch alternative ends in an athrow then the parsing should be
+ // short. If there is no athrow then it is bogus code, anyway.
+ case Bytecodes::_lookupswitch:
+ case Bytecodes::_tableswitch:
+ {
+ address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize);
+ u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci;
+ int keys, delta;
+ if (opcode == Bytecodes::_tableswitch) {
+ jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
+ jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
+ // This is invalid, but let the regular bytecode verifier
+ // report this because the user will get a better error message.
+ if (low > high) return true;
+ keys = high - low + 1;
+ delta = 1;
+ } else {
+ keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
+ delta = 2;
+ }
+ // Invalid, let the regular bytecode verifier deal with it.
+ if (keys < 0) return true;
+
+ // Push the current state onto the stack.
+ push_bci_offsets(bci_stack, bcs.next_bci(), bcs.end_bci());
+
+ // Push the switch alternatives onto the stack.
+ for (int i = 0; i < keys; i++) {
+ u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
+ if (target > code_length) return false;
+ push_bci_offsets(bci_stack, target, code_length);
+ }
+
+ // Start bytecode parsing for the switch at the default alternative.
+ if (default_offset > code_length) return false;
+ bcs.set_interval(default_offset, code_length);
+ break;
+ }
+
+ case Bytecodes::_return:
+ return false;
+
+ case Bytecodes::_athrow:
+ if (bci_stack->is_empty()) {
+ return true;
+ } else {
+ // Pop a bytecode interval and scan that interval.
+ u4 end_offset = pop_bci_end_offset(bci_stack);
+ u4 start_offset = pop_bci_start_offset(bci_stack);
+ assert(end_offset >= start_offset, "Mixed up bytecode offsets");
+ bcs.set_interval(start_offset, end_offset);
+ break;
+ }
+
+ default:
+ ;
+ } // end switch
+ } // end while loop
+
+ return false;
+ }
+
void ClassVerifier::verify_invoke_init(
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
constantPoolHandle cp, TRAPS) {
u2 bci = bcs->bci();
*** 2243,2264 ****
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;
--- 2385,2414 ----
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from inside of a branch");
return;
}
! // Check if this call is done from inside of a TRY block. If so, make
! // sure that all catch clause paths end in a throw. Otherwise, this
! // can result in returning an incomplete object.
ExceptionTable exhandlers(_method());
int exlength = exhandlers.length();
for(int i = 0; i < exlength; i++) {
! u2 start_pc = exhandlers.start_pc(i);
! u2 end_pc = exhandlers.end_pc(i);
!
! if (bci >= start_pc && bci < end_pc) {
! if (!ends_in_athrow(exhandlers.handler_pc(i), code_length)) {
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from after the start of a try block");
return;
+ } else if (VerboseVerification) {
+ ResourceMark rm;
+ tty->print_cr(
+ "Survived call to ends_in_athrow(): %s",
+ current_class()->name()->as_C_string());
+ }
}
}
current_frame->initialize_object(type, current_type());
*this_uninit = true;
src/share/vm/classfile/verifier.cpp
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File