< prev index next >

src/hotspot/share/classfile/verifier.cpp

Print this page
@@ -62,10 +62,11 @@
  #include "utilities/bytes.hpp"
  
  #define NOFAILOVER_MAJOR_VERSION                       51
  #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION  51
  #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION       52
+ #define INLINE_TYPE_MAJOR_VERSION                       56
  #define MAX_ARRAY_DIMENSIONS 255
  
  // Access to external entry for VerifyClassForMajorVersion - old byte code verifier
  
  extern "C" {

@@ -275,11 +276,11 @@
                                  klass->is_subtype_of(refl_serialization_ctor_klass);
  
    return (should_verify_for(klass->class_loader(), should_verify_class) &&
      // return if the class is a bootstrapping class
      // or defineClass specified not to verify by default (flags override passed arg)
-     // We need to skip the following four for bootstraping
+     // We need to skip the following four for bootstrapping
      name != vmSymbols::java_lang_Object() &&
      name != vmSymbols::java_lang_Class() &&
      name != vmSymbols::java_lang_String() &&
      name != vmSymbols::java_lang_Throwable() &&
  

@@ -494,10 +495,17 @@
        ss->print("Expected stackmap frame at this location.");
        break;
      case BAD_STACKMAP:
        ss->print("Invalid stackmap specification.");
        break;
+     case WRONG_INLINE_TYPE:
+       ss->print("Type ");
+       _type.details(ss);
+       ss->print(" and type ");
+       _expected.details(ss);
+       ss->print(" must be identical inline types.");
+       break;
      case UNKNOWN:
      default:
        ShouldNotReachHere();
        ss->print_cr("Unknown");
    }

@@ -614,10 +622,15 @@
    VerificationType vt = VerificationType::reference_type(
                           create_temporary_symbol(sig, (int)strlen(sig)));
    return TypeOrigin::implicit(vt);
  }
  
+ static bool supports_strict_fields(InstanceKlass* klass) {
+   int ver = klass->major_version();
+   return ver > Verifier::VALUE_TYPES_MAJOR_VERSION ||
+          (ver == Verifier::VALUE_TYPES_MAJOR_VERSION && klass->minor_version() == Verifier::JAVA_PREVIEW_MINOR_VERSION);
+ }
  
  void ClassVerifier::verify_class(TRAPS) {
    log_info(verification)("Verifying class %s with new format", _klass->external_name());
  
    // Either verifying both local and remote classes or just remote classes.

@@ -1681,11 +1694,11 @@
                           "Method expects a return value");
              return;
            }
            // Make sure "this" has been initialized if current method is an
            // <init>.
-           if (_method->name() == vmSymbols::object_initializer_name() &&
+           if (_method->is_object_constructor() &&
                current_frame.flag_this_uninit()) {
              verify_error(ErrorContext::bad_code(bci),
                           "Constructor must call super() or this() "
                           "before return");
              return;

@@ -1704,19 +1717,15 @@
              &bcs, &current_frame, cp, false, CHECK_VERIFY(this));
            no_control_flow = false; break;
          case Bytecodes::_invokevirtual :
          case Bytecodes::_invokespecial :
          case Bytecodes::_invokestatic :
-           verify_invoke_instructions(
-             &bcs, code_length, &current_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, &current_frame, (bci >= ex_min && bci < ex_max),
-             &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
+             &this_uninit, cp, &stackmap_table, CHECK_VERIFY(this));
            no_control_flow = false; break;
          case Bytecodes::_new :
          {
            u2 index = bcs.get_index_u2();
            verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));

@@ -1770,14 +1779,15 @@
            current_frame.push_stack(
              VerificationType::integer_type(), CHECK_VERIFY(this));
            no_control_flow = false; break;
          }
          case Bytecodes::_monitorenter :
-         case Bytecodes::_monitorexit :
-           current_frame.pop_stack(
+         case Bytecodes::_monitorexit : {
+           VerificationType ref = current_frame.pop_stack(
              VerificationType::reference_check(), CHECK_VERIFY(this));
            no_control_flow = false; break;
+         }
          case Bytecodes::_multianewarray :
          {
            u2 index = bcs.get_index_u2();
            u2 dim = *(bcs.bcp()+3);
            verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));

@@ -2038,10 +2048,11 @@
    // We must check was_recursively_verified() before we get here.
    guarantee(cp->cache() == nullptr, "not rewritten yet");
  
    verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
    unsigned int tag = cp->tag_at(index).value();
+ 
    if ((types & (1 << tag)) == 0) {
      verify_error(ErrorContext::bad_cp_index(bci, index),
        "Illegal type at constant pool entry %d in class %s",
        index, cp->pool_holder()->external_name());
      return;

@@ -2152,11 +2163,11 @@
    constantTag tag = cp->tag_at(index);
    unsigned int types = 0;
    if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) {
      if (!tag.is_unresolved_klass()) {
        types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float)
-             | (1 << JVM_CONSTANT_String)  | (1 << JVM_CONSTANT_Class)
+             | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class)
              | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType)
              | (1 << JVM_CONSTANT_Dynamic);
        // Note:  The class file parser already verified the legality of
        // MethodHandle and MethodType constants.
        verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));

@@ -2328,17 +2339,18 @@
  
    // Get referenced class type
    VerificationType ref_class_type = cp_ref_index_to_type(
      index, cp, CHECK_VERIFY(this));
    if (!ref_class_type.is_object() &&
-     (!allow_arrays || !ref_class_type.is_array())) {
+       (!allow_arrays || !ref_class_type.is_array())) {
      verify_error(ErrorContext::bad_type(bcs->bci(),
          TypeOrigin::cp(index, ref_class_type)),
          "Expecting reference to class in class %s at constant pool index %d",
          _klass->external_name(), index);
      return;
    }
+ 
    VerificationType target_class_type = ref_class_type;
  
    assert(sizeof(VerificationType) == sizeof(uintptr_t),
          "buffer type must match VerificationType size");
    uintptr_t field_type_buffer[2];

@@ -2376,17 +2388,27 @@
        for (int i = n - 1; i >= 0; i--) {
          current_frame->pop_stack(field_type[i], CHECK_VERIFY(this));
        }
        stack_object_type = current_frame->pop_stack(CHECK_VERIFY(this));
  
-       // The JVMS 2nd edition allows field initialization before the superclass
+       // Field initialization is allowed before the superclass
        // initializer, if the field is defined within the current class.
        fieldDescriptor fd;
-       if (stack_object_type == VerificationType::uninitialized_this_type() &&
-           target_class_type.equals(current_type()) &&
-           _klass->find_local_field(field_name, field_sig, &fd)) {
-         stack_object_type = current_type();
+       bool is_local_field = _klass->find_local_field(field_name, field_sig, &fd) &&
+                             target_class_type.equals(current_type());
+       if (stack_object_type == VerificationType::uninitialized_this_type()) {
+         if (is_local_field) {
+           // Set the type to the current type so the is_assignable check passes.
+           stack_object_type = current_type();
+         }
+       } else if (supports_strict_fields(_klass)) {
+         // `strict` fields are not writable, but only local fields produce verification errors
+         if (is_local_field && fd.access_flags().is_strict()) {
+           verify_error(ErrorContext::bad_code(bci),
+                        "Illegal use of putfield on a strict field");
+           return;
+         }
        }
        is_assignable = target_class_type.is_assignable_from(
          stack_object_type, this, false, CHECK_VERIFY(this));
        if (!is_assignable) {
          verify_error(ErrorContext::bad_type(bci,

@@ -2787,11 +2809,11 @@
    return false;
  }
  
  void ClassVerifier::verify_invoke_instructions(
      RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
-     bool in_try_block, bool *this_uninit, VerificationType return_type,
+     bool in_try_block, bool *this_uninit,
      const 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();
    unsigned int types = 0;

@@ -2819,11 +2841,11 @@
  
    // Method signature was checked in ClassFileParser.
    assert(SignatureVerifier::is_valid_method_signature(method_sig),
           "Invalid method signature");
  
-   // Get referenced class type
+   // Get referenced class
    VerificationType ref_class_type;
    if (opcode == Bytecodes::_invokedynamic) {
      if (_klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
        class_format_error(
          "invokedynamic instructions not supported by this class file version (%d), class %s",

@@ -2885,21 +2907,22 @@
        return;
      }
    }
  
    if (method_name->char_at(0) == JVM_SIGNATURE_SPECIAL) {
-     // Make sure <init> can only be invoked by invokespecial
+     // Make sure:
+     //   <init> can only be invoked by invokespecial.
      if (opcode != Bytecodes::_invokespecial ||
-         method_name != vmSymbols::object_initializer_name()) {
+           method_name != vmSymbols::object_initializer_name()) {
        verify_error(ErrorContext::bad_code(bci),
            "Illegal call to internal method");
        return;
      }
    } else if (opcode == Bytecodes::_invokespecial
               && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type)
               && !ref_class_type.equals(VerificationType::reference_type(
-                   current_class()->super()->name()))) {
+                   current_class()->super()->name()))) { // super() can never be an inline_type.
      bool subtype = false;
      bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref;
      subtype = ref_class_type.is_assignable_from(
                 current_type(), this, false, CHECK_VERIFY(this));
      if (!subtype) {

@@ -2980,13 +3003,11 @@
    }
    // Push the result type.
    int sig_verif_types_len = sig_verif_types->length();
    if (sig_verif_types_len > nargs) {  // There's a return type
      if (method_name == vmSymbols::object_initializer_name()) {
-       // <init> method must have a void return type
-       /* Unreachable?  Class file parser verifies that methods with '<' have
-        * void return */
+       // an <init> method must have a void return type
        verify_error(ErrorContext::bad_code(bci),
            "Return type must be void in <init> method");
        return;
      }
  
< prev index next >