8058982: Better verification of an exceptional invokespecial

Mon, 20 Oct 2014 15:14:56 -0400

author
hseigel
date
Mon, 20 Oct 2014 15:14:56 -0400
changeset 7705
5f07d936a14e
parent 7704
9c5134750f1d
child 7706
37179dcf830a

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, &current_frame,
     1.8 -            &this_uninit, return_type, cp, CHECK_VERIFY(this));
     1.9 +            &bcs, code_length, &current_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, &current_frame,
    1.16 -            &this_uninit, return_type, cp, CHECK_VERIFY(this));
    1.17 +            &bcs, code_length, &current_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,

mercurial