8050485: super() in a try block in a ctor causes VerifyError

Tue, 12 Aug 2014 20:29:25 -0400

author
hseigel
date
Tue, 12 Aug 2014 20:29:25 -0400
changeset 6871
077483254bf6
parent 6870
853a5158a1e2
child 6872
c77d5db18942

8050485: super() in a try block in a ctor causes VerifyError
Summary: Parse catch clause paths to ensure they end in throws
Reviewed-by: dlong, acorn, kamg, ctornqvi, lfoltan

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	Wed Aug 20 15:32:00 2014 -0700
     1.2 +++ b/src/share/vm/classfile/verifier.cpp	Tue Aug 12 20:29:25 2014 -0400
     1.3 @@ -2231,6 +2231,181 @@
     1.4    }
     1.5  }
     1.6  
     1.7 +// Look at the method's handlers.  If the bci is in the handler's try block
     1.8 +// then check if the handler_pc is already on the stack.  If not, push it.
     1.9 +void ClassVerifier::push_handlers(ExceptionTable* exhandlers,
    1.10 +                                  GrowableArray<u4>* handler_stack,
    1.11 +                                  u4 bci) {
    1.12 +  int exlength = exhandlers->length();
    1.13 +  for(int x = 0; x < exlength; x++) {
    1.14 +    if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) {
    1.15 +      handler_stack->append_if_missing(exhandlers->handler_pc(x));
    1.16 +    }
    1.17 +  }
    1.18 +}
    1.19 +
    1.20 +// Return TRUE if all code paths starting with start_bc_offset end in
    1.21 +// bytecode athrow or loop.
    1.22 +bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
    1.23 +  ResourceMark rm;
    1.24 +  // Create bytecode stream.
    1.25 +  RawBytecodeStream bcs(method());
    1.26 +  u4 code_length = method()->code_size();
    1.27 +  bcs.set_start(start_bc_offset);
    1.28 +  u4 target;
    1.29 +  // Create stack for storing bytecode start offsets for if* and *switch.
    1.30 +  GrowableArray<u4>* bci_stack = new GrowableArray<u4>(30);
    1.31 +  // Create stack for handlers for try blocks containing this handler.
    1.32 +  GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30);
    1.33 +  // Create list of visited branch opcodes (goto* and if*).
    1.34 +  GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30);
    1.35 +  ExceptionTable exhandlers(_method());
    1.36 +
    1.37 +  while (true) {
    1.38 +    if (bcs.is_last_bytecode()) {
    1.39 +      // if no more starting offsets to parse or if at the end of the
    1.40 +      // method then return false.
    1.41 +      if ((bci_stack->is_empty()) || ((u4)bcs.end_bci() == code_length))
    1.42 +        return false;
    1.43 +      // Pop a bytecode starting offset and scan from there.
    1.44 +      bcs.set_start(bci_stack->pop());
    1.45 +    }
    1.46 +    Bytecodes::Code opcode = bcs.raw_next();
    1.47 +    u4 bci = bcs.bci();
    1.48 +
    1.49 +    // If the bytecode is in a TRY block, push its handlers so they
    1.50 +    // will get parsed.
    1.51 +    push_handlers(&exhandlers, handler_stack, bci);
    1.52 +
    1.53 +    switch (opcode) {
    1.54 +      case Bytecodes::_if_icmpeq:
    1.55 +      case Bytecodes::_if_icmpne:
    1.56 +      case Bytecodes::_if_icmplt:
    1.57 +      case Bytecodes::_if_icmpge:
    1.58 +      case Bytecodes::_if_icmpgt:
    1.59 +      case Bytecodes::_if_icmple:
    1.60 +      case Bytecodes::_ifeq:
    1.61 +      case Bytecodes::_ifne:
    1.62 +      case Bytecodes::_iflt:
    1.63 +      case Bytecodes::_ifge:
    1.64 +      case Bytecodes::_ifgt:
    1.65 +      case Bytecodes::_ifle:
    1.66 +      case Bytecodes::_if_acmpeq:
    1.67 +      case Bytecodes::_if_acmpne:
    1.68 +      case Bytecodes::_ifnull:
    1.69 +      case Bytecodes::_ifnonnull:
    1.70 +        target = bcs.dest();
    1.71 +        if (visited_branches->contains(bci)) {
    1.72 +          if (bci_stack->is_empty()) return true;
    1.73 +          // Pop a bytecode starting offset and scan from there.
    1.74 +          bcs.set_start(bci_stack->pop());
    1.75 +        } else {
    1.76 +          if (target > bci) { // forward branch
    1.77 +            if (target >= code_length) return false;
    1.78 +            // Push the branch target onto the stack.
    1.79 +            bci_stack->push(target);
    1.80 +            // then, scan bytecodes starting with next.
    1.81 +            bcs.set_start(bcs.next_bci());
    1.82 +          } else { // backward branch
    1.83 +            // Push bytecode offset following backward branch onto the stack.
    1.84 +            bci_stack->push(bcs.next_bci());
    1.85 +            // Check bytecodes starting with branch target.
    1.86 +            bcs.set_start(target);
    1.87 +          }
    1.88 +          // Record target so we don't branch here again.
    1.89 +          visited_branches->append(bci);
    1.90 +        }
    1.91 +        break;
    1.92 +
    1.93 +      case Bytecodes::_goto:
    1.94 +      case Bytecodes::_goto_w:
    1.95 +        target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
    1.96 +        if (visited_branches->contains(bci)) {
    1.97 +          if (bci_stack->is_empty()) return true;
    1.98 +          // Been here before, pop new starting offset from stack.
    1.99 +          bcs.set_start(bci_stack->pop());
   1.100 +        } else {
   1.101 +          if (target >= code_length) return false;
   1.102 +          // Continue scanning from the target onward.
   1.103 +          bcs.set_start(target);
   1.104 +          // Record target so we don't branch here again.
   1.105 +          visited_branches->append(bci);
   1.106 +        }
   1.107 +        break;
   1.108 +
   1.109 +      // Check that all switch alternatives end in 'athrow' bytecodes. Since it
   1.110 +      // is  difficult to determine where each switch alternative ends, parse
   1.111 +      // each switch alternative until either hit a 'return', 'athrow', or reach
   1.112 +      // the end of the method's bytecodes.  This is gross but should be okay
   1.113 +      // because:
   1.114 +      // 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit
   1.115 +      //    constructor invocations should be rare.
   1.116 +      // 2. if each switch alternative ends in an athrow then the parsing should be
   1.117 +      //    short.  If there is no athrow then it is bogus code, anyway.
   1.118 +      case Bytecodes::_lookupswitch:
   1.119 +      case Bytecodes::_tableswitch:
   1.120 +        {
   1.121 +          address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize);
   1.122 +          u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci;
   1.123 +          int keys, delta;
   1.124 +          if (opcode == Bytecodes::_tableswitch) {
   1.125 +            jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
   1.126 +            jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
   1.127 +            // This is invalid, but let the regular bytecode verifier
   1.128 +            // report this because the user will get a better error message.
   1.129 +            if (low > high) return true;
   1.130 +            keys = high - low + 1;
   1.131 +            delta = 1;
   1.132 +          } else {
   1.133 +            keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
   1.134 +            delta = 2;
   1.135 +          }
   1.136 +          // Invalid, let the regular bytecode verifier deal with it.
   1.137 +          if (keys < 0) return true;
   1.138 +
   1.139 +          // Push the offset of the next bytecode onto the stack.
   1.140 +          bci_stack->push(bcs.next_bci());
   1.141 +
   1.142 +          // Push the switch alternatives onto the stack.
   1.143 +          for (int i = 0; i < keys; i++) {
   1.144 +            u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize);
   1.145 +            if (target > code_length) return false;
   1.146 +            bci_stack->push(target);
   1.147 +          }
   1.148 +
   1.149 +          // Start bytecode parsing for the switch at the default alternative.
   1.150 +          if (default_offset > code_length) return false;
   1.151 +          bcs.set_start(default_offset);
   1.152 +          break;
   1.153 +        }
   1.154 +
   1.155 +      case Bytecodes::_return:
   1.156 +        return false;
   1.157 +
   1.158 +      case Bytecodes::_athrow:
   1.159 +        {
   1.160 +          if (bci_stack->is_empty()) {
   1.161 +            if (handler_stack->is_empty()) {
   1.162 +              return true;
   1.163 +            } else {
   1.164 +              // Parse the catch handlers for try blocks containing athrow.
   1.165 +              bcs.set_start(handler_stack->pop());
   1.166 +            }
   1.167 +          } else {
   1.168 +            // Pop a bytecode offset and starting scanning from there.
   1.169 +            bcs.set_start(bci_stack->pop());
   1.170 +          }
   1.171 +        }
   1.172 +        break;
   1.173 +
   1.174 +      default:
   1.175 +        ;
   1.176 +    } // end switch
   1.177 +  } // end while loop
   1.178 +
   1.179 +  return false;
   1.180 +}
   1.181 +
   1.182  void ClassVerifier::verify_invoke_init(
   1.183      RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
   1.184      StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
   1.185 @@ -2250,18 +2425,26 @@
   1.186        return;
   1.187      }
   1.188  
   1.189 -    // Make sure that this call is not done from within a TRY block because
   1.190 -    // that can result in returning an incomplete object.  Simply checking
   1.191 -    // (bci >= start_pc) also ensures that this call is not done after a TRY
   1.192 -    // block.  That is also illegal because this call must be the first Java
   1.193 -    // statement in the constructor.
   1.194 +    // Check if this call is done from inside of a TRY block.  If so, make
   1.195 +    // sure that all catch clause paths end in a throw.  Otherwise, this
   1.196 +    // can result in returning an incomplete object.
   1.197      ExceptionTable exhandlers(_method());
   1.198      int exlength = exhandlers.length();
   1.199      for(int i = 0; i < exlength; i++) {
   1.200 -      if (bci >= exhandlers.start_pc(i)) {
   1.201 -        verify_error(ErrorContext::bad_code(bci),
   1.202 -                     "Bad <init> method call from after the start of a try block");
   1.203 -        return;
   1.204 +      u2 start_pc = exhandlers.start_pc(i);
   1.205 +      u2 end_pc = exhandlers.end_pc(i);
   1.206 +
   1.207 +      if (bci >= start_pc && bci < end_pc) {
   1.208 +        if (!ends_in_athrow(exhandlers.handler_pc(i))) {
   1.209 +          verify_error(ErrorContext::bad_code(bci),
   1.210 +            "Bad <init> method call from after the start of a try block");
   1.211 +          return;
   1.212 +        } else if (VerboseVerification) {
   1.213 +          ResourceMark rm;
   1.214 +          tty->print_cr(
   1.215 +            "Survived call to ends_in_athrow(): %s",
   1.216 +                        current_class()->name()->as_C_string());
   1.217 +        }
   1.218        }
   1.219      }
   1.220  
     2.1 --- a/src/share/vm/classfile/verifier.hpp	Wed Aug 20 15:32:00 2014 -0700
     2.2 +++ b/src/share/vm/classfile/verifier.hpp	Tue Aug 12 20:29:25 2014 -0400
     2.3 @@ -30,6 +30,7 @@
     2.4  #include "oops/klass.hpp"
     2.5  #include "oops/method.hpp"
     2.6  #include "runtime/handles.hpp"
     2.7 +#include "utilities/growableArray.hpp"
     2.8  #include "utilities/exceptions.hpp"
     2.9  
    2.10  // The verifier class
    2.11 @@ -303,6 +304,16 @@
    2.12      StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
    2.13      constantPoolHandle cp, TRAPS);
    2.14  
    2.15 +  // Used by ends_in_athrow() to push all handlers that contain bci onto
    2.16 +  // the handler_stack, if the handler is not already on the stack.
    2.17 +  void push_handlers(ExceptionTable* exhandlers,
    2.18 +                     GrowableArray<u4>* handler_stack,
    2.19 +                     u4 bci);
    2.20 +
    2.21 +  // Returns true if all paths starting with start_bc_offset end in athrow
    2.22 +  // bytecode or loop.
    2.23 +  bool ends_in_athrow(u4 start_bc_offset);
    2.24 +
    2.25    void verify_invoke_instructions(
    2.26      RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
    2.27      bool* this_uninit, VerificationType return_type,

mercurial