# HG changeset patch # User hseigel # Date 1413837051 14400 # Node ID d12c9850a885f7dee2ef52094bb080b2bc6cfd32 # Parent d94b62f63b37db7039438bdd4dd9ac62dda9e33a 8058982: Better verification of an exceptional invokespecial Reviewed-by: acorn, ahgross, coleenp Contributed-by: harold.seigel@oracle.com diff -r d94b62f63b37 -r d12c9850a885 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Tue Oct 21 11:39:21 2014 -0700 +++ b/src/share/vm/classfile/verifier.cpp Mon Oct 20 16:30:51 2014 -0400 @@ -1549,14 +1549,14 @@ case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokeinterface : case Bytecodes::_invokedynamic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_new : { @@ -2399,8 +2399,9 @@ 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) { + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS) { u2 bci = bcs->bci(); VerificationType type = current_frame->pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); @@ -2416,28 +2417,38 @@ 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 this invokespecial call is done from inside of a TRY block then make + // sure that all catch clause paths end in a throw. Otherwise, this can + // result in returning an incomplete object. + if (in_try_block) { + ExceptionTable exhandlers(_method()); + int exlength = exhandlers.length(); + for(int i = 0; i < exlength; i++) { + // Reacquire the table in case a GC happened + ExceptionTable exhandlers(_method()); + 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))) { - verify_error(ErrorContext::bad_code(bci), - "Bad 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()); + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad 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()); + } } } - } + + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + verify_exception_handler_targets(bci, true, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } // in_try_block current_frame->initialize_object(type, current_type()); *this_uninit = true; @@ -2493,6 +2504,13 @@ } } } + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + if (in_try_block) { + verify_exception_handler_targets(bci, *this_uninit, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } current_frame->initialize_object(type, new_class_type); } else { verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), @@ -2503,8 +2521,8 @@ void ClassVerifier::verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool *this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS) { + bool in_try_block, bool *this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { // Make sure the constant pool item is the right type u2 index = bcs->get_index_u2(); Bytecodes::Code opcode = bcs->raw_code(); @@ -2640,7 +2658,8 @@ opcode != Bytecodes::_invokedynamic) { if (method_name == vmSymbols::object_initializer_name()) { // method verify_invoke_init(bcs, index, ref_class_type, current_frame, - code_length, this_uninit, cp, CHECK_VERIFY(this)); + code_length, in_try_block, this_uninit, cp, stackmap_table, + CHECK_VERIFY(this)); } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) { diff -r d94b62f63b37 -r d12c9850a885 src/share/vm/classfile/verifier.hpp --- a/src/share/vm/classfile/verifier.hpp Tue Oct 21 11:39:21 2014 -0700 +++ b/src/share/vm/classfile/verifier.hpp Mon Oct 20 16:30:51 2014 -0400 @@ -299,8 +299,9 @@ void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, - constantPoolHandle cp, TRAPS); + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + 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. @@ -314,8 +315,8 @@ void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool* this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS); + bool in_try_block, bool* this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,