< prev index next >

src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java

Print this page
*** 22,12 ***
--- 22,15 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package jdk.internal.classfile.impl.verifier;
  
+ import java.lang.classfile.constantpool.NameAndTypeEntry;
  import java.util.ArrayList;
+ import java.util.HashSet;
  import java.util.List;
+ import java.util.Set;
  
  import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object;
  import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized;
  import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis;
  

*** 127,10 ***
--- 130,11 ---
              frame.set_locals_size(lsize);
              frame.copy_locals(stackmap_frame);
              frame.set_stack_size(ssize);
              frame.copy_stack(stackmap_frame);
              frame.set_flags(stackmap_frame.flags());
+             frame.set_assert_unset_fields(stackmap_frame.assert_unset_fields());
          }
          return result;
      }
  
      void check_jump_target(VerificationFrame frame, int target) {

*** 148,22 ***
--- 152,26 ---
          private final int _code_length;
          private final int _frame_count;
          private int _parsed_frame_count;
          private VerificationFrame _prev_frame;
          char _max_locals, _max_stack;
+         final Set<NameAndTypeEntry> strictFields;
+         Set<NameAndTypeEntry> _assert_unset_fields_buffer;
          boolean _first;
  
          void check_verification_type_array_size(int size, int max_size) {
              if (size < 0 || size > max_size) {
                  _verifier.classError("StackMapTable format error: bad type array size");
              }
          }
  
          private static final int
+                         EARLY_LARVAL = 246,
                          SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
                          SAME_EXTENDED = 251,
                          FULL = 255;
+         private static final int RESERVED_TAGS_UPPER_LIMIT = EARLY_LARVAL; // not inclusive
  
          public int get_frame_count() {
              return _frame_count;
          }
  

*** 202,19 ***
--- 210,22 ---
  
          private final VerifierImpl _verifier;
  
          public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len,
                                VerificationFrame init_frame, char max_locals, char max_stack,
+                               Set<NameAndTypeEntry> initial_strict_fields,
                                VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) {
              this._verifier = context;
              _stream = new StackMapStream(stackmapData, _verifier);
              _code_data = code_data;
              _code_length = code_len;
              _parsed_frame_count = 0;
              _prev_frame = init_frame;
              _max_locals = max_locals;
              _max_stack = max_stack;
+             strictFields = Set.copyOf(initial_strict_fields);
+             _assert_unset_fields_buffer = initial_strict_fields;
              _first = true;
              if (stackmapData != null) {
                  _cp = cp;
                  _frame_count = _stream.get_u2();
              } else {

*** 283,21 ***
          VerificationFrame next_helper() {
              VerificationFrame frame;
              int offset;
              VerificationType[] locals = null;
              int frame_type = _stream.get_u1();
              if (frame_type < 64) {
                  if (_first) {
                      offset = frame_type;
                      if (_prev_frame.locals_size() > 0) {
                          locals = new VerificationType[_prev_frame.locals_size()];
                      }
                  } else {
                      offset = _prev_frame.offset() + frame_type + 1;
                      locals = _prev_frame.locals();
                  }
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;
--- 294,56 ---
          VerificationFrame next_helper() {
              VerificationFrame frame;
              int offset;
              VerificationType[] locals = null;
              int frame_type = _stream.get_u1();
+             if (frame_type == EARLY_LARVAL) {
+                 int num_unset_fields = _stream.get_u2();
+                 Set<NameAndTypeEntry> new_fields = new HashSet<>();
+                 for (int i = 0; i < num_unset_fields; i++) {
+                     int index = _stream.get_u2();
+                     if (!_cp.is_within_bounds(index) || _cp.tagAt(index) != VerifierImpl.JVM_CONSTANT_NameAndType) {
+                         _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+                                 "Invalid constant pool index in early larval frame: %d".formatted(index)));
+                     }
+                     var tmp = _cp.cp.entryByIndex(index, NameAndTypeEntry.class);
+                     if (!strictFields.contains(tmp)) {
+                         _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+                                 "Strict fields not a subset of initial strict instance fields: %s".formatted(tmp)));
+                     } else {
+                         new_fields.add(tmp);
+                     }
+                 }
+                 // Only modify strict instance fields the frame has uninitialized this
+                 if (_prev_frame.flag_this_uninit()) {
+                     _assert_unset_fields_buffer = _prev_frame.merge_unset_fields(new_fields);
+                 } else if (!new_fields.isEmpty()) {
+                     _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+                             "Cannot have uninitialized strict fields after class initialization"));
+                 }
+                 // Continue reading frame data
+                 if (at_end()) {
+                     _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+                             "Early larval frame must be followed by a base frame"));
+                 }
+                 frame_type = _stream.get_u1();
+                 if (frame_type == EARLY_LARVAL) {
+                     _prev_frame.verifier().verifyError("Invalid use of strict instance fields %d %s %s".formatted(_prev_frame.offset(), _prev_frame,
+                             "Early larval frame must be followed by a base frame"));
+                 }
+             }
              if (frame_type < 64) {
                  if (_first) {
                      offset = frame_type;
                      if (_prev_frame.locals_size() > 0) {
                          locals = new VerificationType[_prev_frame.locals_size()];
                      }
                  } else {
                      offset = _prev_frame.offset() + frame_type + 1;
                      locals = _prev_frame.locals();
                  }
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;

*** 318,19 ***
                  if (stack[0].is_category2()) {
                      stack[1] = stack[0].to_category2_2nd(_verifier);
                      stack_size = 2;
                  }
                  check_verification_type_array_size(stack_size, _max_stack);
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;
              }
              int offset_delta = _stream.get_u2();
!             if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
                  _verifier.classError("reserved frame type");
              }
              if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
                  if (_first) {
                      offset = offset_delta;
--- 364,19 ---
                  if (stack[0].is_category2()) {
                      stack[1] = stack[0].to_category2_2nd(_verifier);
                      stack_size = 2;
                  }
                  check_verification_type_array_size(stack_size, _max_stack);
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;
              }
              int offset_delta = _stream.get_u2();
!             if (frame_type < RESERVED_TAGS_UPPER_LIMIT) {
                  _verifier.classError("reserved frame type");
              }
              if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
                  if (_first) {
                      offset = offset_delta;

*** 347,11 ***
                  if (stack[0].is_category2()) {
                      stack[1] = stack[0].to_category2_2nd(_verifier);
                      stack_size = 2;
                  }
                  check_verification_type_array_size(stack_size, _max_stack);
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;
--- 393,11 ---
                  if (stack[0].is_category2()) {
                      stack[1] = stack[0].to_category2_2nd(_verifier);
                      stack_size = 2;
                  }
                  check_verification_type_array_size(stack_size, _max_stack);
!                 frame = new VerificationFrame(offset, _prev_frame.flags(), _prev_frame.locals_size(), stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;

*** 381,11 ***
                          locals = null;
                      }
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;
--- 427,11 ---
                          locals = null;
                      }
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags, new_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
                  if (_first && locals != null) {
                      frame.copy_locals(_prev_frame);
                  }
                  _first = false;
                  return frame;

*** 412,11 ***
                  if (_first) {
                      offset = offset_delta;
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _verifier);
                  _first = false;
                  return frame;
              }
              if (frame_type == FULL) {
                  int flags[] = new int[]{0};
--- 458,11 ---
                  if (_first) {
                      offset = offset_delta;
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags[0], real_length, 0, _max_locals, _max_stack, locals, null, _assert_unset_fields_buffer, _verifier);
                  _first = false;
                  return frame;
              }
              if (frame_type == FULL) {
                  int flags[] = new int[]{0};

*** 454,11 ***
                  if (_first) {
                      offset = offset_delta;
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _verifier);
                  _first = false;
                  return frame;
              }
              _verifier.classError("reserved frame type");
              return null;
--- 500,11 ---
                  if (_first) {
                      offset = offset_delta;
                  } else {
                      offset = _prev_frame.offset() + offset_delta + 1;
                  }
!                 frame = new VerificationFrame(offset, flags[0], real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, _assert_unset_fields_buffer, _verifier);
                  _first = false;
                  return frame;
              }
              _verifier.classError("reserved frame type");
              return null;
< prev index next >