Mon, 20 Oct 2014 15:14:56 -0400
8058982: Better verification of an exceptional invokespecial
Summary: Throw VerifyError for illegal accesses
Reviewed-by: acorn, ahgross, coleenp
src/share/vm/classfile/verifier.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/classfile/verifier.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/classfile/verifier.cpp Sun Oct 19 21:00:56 2014 -0700 1.2 +++ b/src/share/vm/classfile/verifier.cpp Mon Oct 20 15:14:56 2014 -0400 1.3 @@ -1553,14 +1553,14 @@ 1.4 case Bytecodes::_invokespecial : 1.5 case Bytecodes::_invokestatic : 1.6 verify_invoke_instructions( 1.7 - &bcs, code_length, ¤t_frame, 1.8 - &this_uninit, return_type, cp, CHECK_VERIFY(this)); 1.9 + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), 1.10 + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); 1.11 no_control_flow = false; break; 1.12 case Bytecodes::_invokeinterface : 1.13 case Bytecodes::_invokedynamic : 1.14 verify_invoke_instructions( 1.15 - &bcs, code_length, ¤t_frame, 1.16 - &this_uninit, return_type, cp, CHECK_VERIFY(this)); 1.17 + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), 1.18 + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); 1.19 no_control_flow = false; break; 1.20 case Bytecodes::_new : 1.21 { 1.22 @@ -2408,8 +2408,9 @@ 1.23 1.24 void ClassVerifier::verify_invoke_init( 1.25 RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, 1.26 - StackMapFrame* current_frame, u4 code_length, bool *this_uninit, 1.27 - constantPoolHandle cp, TRAPS) { 1.28 + StackMapFrame* current_frame, u4 code_length, bool in_try_block, 1.29 + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, 1.30 + TRAPS) { 1.31 u2 bci = bcs->bci(); 1.32 VerificationType type = current_frame->pop_stack( 1.33 VerificationType::reference_check(), CHECK_VERIFY(this)); 1.34 @@ -2425,28 +2426,36 @@ 1.35 return; 1.36 } 1.37 1.38 - // Check if this call is done from inside of a TRY block. If so, make 1.39 - // sure that all catch clause paths end in a throw. Otherwise, this 1.40 - // can result in returning an incomplete object. 1.41 - ExceptionTable exhandlers(_method()); 1.42 - int exlength = exhandlers.length(); 1.43 - for(int i = 0; i < exlength; i++) { 1.44 - u2 start_pc = exhandlers.start_pc(i); 1.45 - u2 end_pc = exhandlers.end_pc(i); 1.46 + // If this invokespecial call is done from inside of a TRY block then make 1.47 + // sure that all catch clause paths end in a throw. Otherwise, this can 1.48 + // result in returning an incomplete object. 1.49 + if (in_try_block) { 1.50 + ExceptionTable exhandlers(_method()); 1.51 + int exlength = exhandlers.length(); 1.52 + for(int i = 0; i < exlength; i++) { 1.53 + u2 start_pc = exhandlers.start_pc(i); 1.54 + u2 end_pc = exhandlers.end_pc(i); 1.55 1.56 - if (bci >= start_pc && bci < end_pc) { 1.57 - if (!ends_in_athrow(exhandlers.handler_pc(i))) { 1.58 - verify_error(ErrorContext::bad_code(bci), 1.59 - "Bad <init> method call from after the start of a try block"); 1.60 - return; 1.61 - } else if (VerboseVerification) { 1.62 - ResourceMark rm; 1.63 - tty->print_cr( 1.64 - "Survived call to ends_in_athrow(): %s", 1.65 - current_class()->name()->as_C_string()); 1.66 + if (bci >= start_pc && bci < end_pc) { 1.67 + if (!ends_in_athrow(exhandlers.handler_pc(i))) { 1.68 + verify_error(ErrorContext::bad_code(bci), 1.69 + "Bad <init> method call from after the start of a try block"); 1.70 + return; 1.71 + } else if (VerboseVerification) { 1.72 + ResourceMark rm; 1.73 + tty->print_cr( 1.74 + "Survived call to ends_in_athrow(): %s", 1.75 + current_class()->name()->as_C_string()); 1.76 + } 1.77 } 1.78 } 1.79 - } 1.80 + 1.81 + // Check the exception handler target stackmaps with the locals from the 1.82 + // incoming stackmap (before initialize_object() changes them to outgoing 1.83 + // state). 1.84 + verify_exception_handler_targets(bci, true, current_frame, 1.85 + stackmap_table, CHECK_VERIFY(this)); 1.86 + } // in_try_block 1.87 1.88 current_frame->initialize_object(type, current_type()); 1.89 *this_uninit = true; 1.90 @@ -2500,6 +2509,13 @@ 1.91 } 1.92 } 1.93 } 1.94 + // Check the exception handler target stackmaps with the locals from the 1.95 + // incoming stackmap (before initialize_object() changes them to outgoing 1.96 + // state). 1.97 + if (in_try_block) { 1.98 + verify_exception_handler_targets(bci, *this_uninit, current_frame, 1.99 + stackmap_table, CHECK_VERIFY(this)); 1.100 + } 1.101 current_frame->initialize_object(type, new_class_type); 1.102 } else { 1.103 verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), 1.104 @@ -2528,8 +2544,8 @@ 1.105 1.106 void ClassVerifier::verify_invoke_instructions( 1.107 RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, 1.108 - bool *this_uninit, VerificationType return_type, 1.109 - constantPoolHandle cp, TRAPS) { 1.110 + bool in_try_block, bool *this_uninit, VerificationType return_type, 1.111 + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { 1.112 // Make sure the constant pool item is the right type 1.113 u2 index = bcs->get_index_u2(); 1.114 Bytecodes::Code opcode = bcs->raw_code(); 1.115 @@ -2699,7 +2715,8 @@ 1.116 opcode != Bytecodes::_invokedynamic) { 1.117 if (method_name == vmSymbols::object_initializer_name()) { // <init> method 1.118 verify_invoke_init(bcs, index, ref_class_type, current_frame, 1.119 - code_length, this_uninit, cp, CHECK_VERIFY(this)); 1.120 + code_length, in_try_block, this_uninit, cp, stackmap_table, 1.121 + CHECK_VERIFY(this)); 1.122 } else { // other methods 1.123 // Ensures that target class is assignable to method class. 1.124 if (opcode == Bytecodes::_invokespecial) {
2.1 --- a/src/share/vm/classfile/verifier.hpp Sun Oct 19 21:00:56 2014 -0700 2.2 +++ b/src/share/vm/classfile/verifier.hpp Mon Oct 20 15:14:56 2014 -0400 2.3 @@ -301,8 +301,9 @@ 2.4 2.5 void verify_invoke_init( 2.6 RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, 2.7 - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, 2.8 - constantPoolHandle cp, TRAPS); 2.9 + StackMapFrame* current_frame, u4 code_length, bool in_try_block, 2.10 + bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, 2.11 + TRAPS); 2.12 2.13 // Used by ends_in_athrow() to push all handlers that contain bci onto 2.14 // the handler_stack, if the handler is not already on the stack. 2.15 @@ -316,8 +317,8 @@ 2.16 2.17 void verify_invoke_instructions( 2.18 RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, 2.19 - bool* this_uninit, VerificationType return_type, 2.20 - constantPoolHandle cp, TRAPS); 2.21 + bool in_try_block, bool* this_uninit, VerificationType return_type, 2.22 + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); 2.23 2.24 VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); 2.25 void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,