--- old/src/hotspot/share/classfile/verifier.cpp 2019-03-11 14:25:41.534355496 +0100 +++ new/src/hotspot/share/classfile/verifier.cpp 2019-03-11 14:25:41.330355499 +0100 @@ -58,6 +58,7 @@ #define NOFAILOVER_MAJOR_VERSION 51 #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51 #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 +#define VALUETYPE_MAJOR_VERSION 56 #define MAX_ARRAY_DIMENSIONS 255 // Access to external entry for VerifyClassCodes - old byte code verifier @@ -242,7 +243,7 @@ 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() && @@ -473,6 +474,13 @@ case BAD_STACKMAP: ss->print("Invalid stackmap specification."); break; + case WRONG_VALUE_TYPE: + ss->print("Type "); + _type.details(ss); + ss->print(" and type "); + _expected.details(ss); + ss->print(" must be identical value types."); + break; case UNKNOWN: default: ShouldNotReachHere(); @@ -567,10 +575,18 @@ // Methods in ClassVerifier +VerificationType reference_or_valuetype(InstanceKlass* klass) { + if (klass->is_value()) { + return VerificationType::valuetype_type(klass->name()); + } else { + return VerificationType::reference_type(klass->name()); + } +} + ClassVerifier::ClassVerifier( InstanceKlass* klass, TRAPS) : _thread(THREAD), _exception_type(NULL), _message(NULL), _klass(klass) { - _this_type = VerificationType::reference_type(klass->name()); + _this_type = reference_or_valuetype(klass); // Create list to hold symbols in reference area. _symbols = new GrowableArray(100, 0, NULL); } @@ -960,7 +976,7 @@ VerificationType::integer_type(), CHECK_VERIFY(this)); atype = current_frame.pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); - if (!atype.is_reference_array()) { + if (!atype.is_nonscalar_array()) { verify_error(ErrorContext::bad_type(bci, current_frame.stack_top_ctx(), TypeOrigin::implicit(VerificationType::reference_check())), @@ -1134,7 +1150,7 @@ atype = current_frame.pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); // more type-checking is done at runtime - if (!atype.is_reference_array()) { + if (!atype.is_nonscalar_array()) { verify_error(ErrorContext::bad_type(bci, current_frame.stack_top_ctx(), TypeOrigin::implicit(VerificationType::reference_check())), @@ -1534,12 +1550,12 @@ case Bytecodes::_if_acmpeq : case Bytecodes::_if_acmpne : current_frame.pop_stack( - VerificationType::reference_check(), CHECK_VERIFY(this)); + VerificationType::nonscalar_check(), CHECK_VERIFY(this)); // fall through case Bytecodes::_ifnull : case Bytecodes::_ifnonnull : current_frame.pop_stack( - VerificationType::reference_check(), CHECK_VERIFY(this)); + VerificationType::nonscalar_check(), CHECK_VERIFY(this)); target = bcs.dest(); stackmap_table.check_jump_target (¤t_frame, target, CHECK_VERIFY(this)); @@ -1590,7 +1606,7 @@ no_control_flow = true; break; case Bytecodes::_areturn : type = current_frame.pop_stack( - VerificationType::reference_check(), CHECK_VERIFY(this)); + VerificationType::nonscalar_check(), CHECK_VERIFY(this)); verify_return_value(return_type, type, bci, ¤t_frame, CHECK_VERIFY(this)); no_control_flow = true; break; @@ -1622,6 +1638,17 @@ verify_field_instructions( &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); no_control_flow = false; break; + case Bytecodes::_withfield : + if (_klass->major_version() < VALUETYPE_MAJOR_VERSION) { + class_format_error( + "withfield not supported by this class file version (%d.%d), class %s", + _klass->major_version(), _klass->minor_version(), _klass->external_name()); + return; + } + // pass FALSE, operand can't be an array type for withfield. + verify_field_instructions( + &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); + no_control_flow = false; break; case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : @@ -1651,6 +1678,28 @@ current_frame.push_stack(type, CHECK_VERIFY(this)); no_control_flow = false; break; } + case Bytecodes::_defaultvalue : + { + if (_klass->major_version() < VALUETYPE_MAJOR_VERSION) { + class_format_error( + "defaultvalue not supported by this class file version (%d.%d), class %s", + _klass->major_version(), _klass->minor_version(), _klass->external_name()); + return; + } + index = bcs.get_index_u2(); + verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this)); + VerificationType ref_type = cp_index_to_type(index, cp, CHECK_VERIFY(this)); + if (!ref_type.is_object()) { + verify_error(ErrorContext::bad_type(bci, + TypeOrigin::cp(index, ref_type)), + "Illegal defaultvalue instruction"); + return; + } + VerificationType value_type = + VerificationType::change_ref_to_valuetype(ref_type); + current_frame.push_stack(value_type, CHECK_VERIFY(this)); + no_control_flow = false; break; + } case Bytecodes::_newarray : type = get_newarray_type(bcs.get_index(), bci, CHECK_VERIFY(this)); current_frame.pop_stack( @@ -1691,10 +1740,11 @@ 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 : { index = bcs.get_index_u2(); @@ -1953,6 +2003,7 @@ 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", @@ -2063,7 +2114,7 @@ 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 @@ -2246,13 +2297,14 @@ 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), @@ -2283,6 +2335,25 @@ } break; } + case Bytecodes::_withfield: { + for (int i = n - 1; i >= 0; i--) { + current_frame->pop_stack(field_type[i], CHECK_VERIFY(this)); + } + // stack_object_type and target_class_type must be the same value type. + stack_object_type = + current_frame->pop_stack(VerificationType::valuetype_check(), CHECK_VERIFY(this)); + VerificationType target_value_type = + VerificationType::change_ref_to_valuetype(target_class_type); + if (!stack_object_type.equals(target_value_type)) { + verify_error(ErrorContext::bad_value_type(bci, + current_frame->stack_top_ctx(), + TypeOrigin::cp(index, target_class_type)), + "Invalid type on operand stack in withfield instruction"); + return; + } + current_frame->push_stack(target_value_type, CHECK_VERIFY(this)); + break; + } case Bytecodes::_getfield: { stack_object_type = current_frame->pop_stack( target_class_type, CHECK_VERIFY(this)); @@ -2726,7 +2797,7 @@ return; } - // Get referenced class type + // Get referenced class VerificationType ref_class_type; if (opcode == Bytecodes::_invokedynamic) { if (_klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { @@ -2818,22 +2889,22 @@ } 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 a value_type. bool subtype = false; bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref; if (!current_class()->is_unsafe_anonymous()) { subtype = ref_class_type.is_assignable_from( current_type(), this, false, CHECK_VERIFY(this)); } else { - VerificationType unsafe_anonymous_host_type = - VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name()); + InstanceKlass* unsafe_host = current_class()->unsafe_anonymous_host(); + VerificationType unsafe_anonymous_host_type = reference_or_valuetype(unsafe_host); subtype = ref_class_type.is_assignable_from(unsafe_anonymous_host_type, this, false, CHECK_VERIFY(this)); // If invokespecial of IMR, need to recheck for same or // direct interface relative to the host class have_imr_indirect = (have_imr_indirect && !is_same_or_direct_interface( - current_class()->unsafe_anonymous_host(), + unsafe_host, unsafe_anonymous_host_type, ref_class_type)); } if (!subtype) { @@ -2871,9 +2942,10 @@ // objectref is a subtype of the unsafe_anonymous_host of the current class // to allow an anonymous class to reference methods in the unsafe_anonymous_host VerificationType top = current_frame->pop_stack(CHECK_VERIFY(this)); - VerificationType hosttype = - VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name()); - bool subtype = hosttype.is_assignable_from(top, this, false, CHECK_VERIFY(this)); + + InstanceKlass* unsafe_host = current_class()->unsafe_anonymous_host(); + VerificationType host_type = reference_or_valuetype(unsafe_host); + bool subtype = host_type.is_assignable_from(top, this, false, CHECK_VERIFY(this)); if (!subtype) { verify_error( ErrorContext::bad_type(current_frame->offset(), current_frame->stack_top_ctx(), @@ -2986,10 +3058,11 @@ assert(n == length, "Unexpected number of characters in string"); } else { // it's an object or interface const char* component_name = component_type.name()->as_utf8(); - // add one dimension to component with 'L' prepended and ';' postpended. + char Q_or_L = component_type.is_valuetype() ? 'Q' : 'L'; + // add one dimension to component with 'L' or 'Q' prepended and ';' appended. length = (int)strlen(component_name) + 3; arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1); - int n = os::snprintf(arr_sig_str, length + 1, "[L%s;", component_name); + int n = os::snprintf(arr_sig_str, length + 1, "[%c%s;", Q_or_L, component_name); assert(n == length, "Unexpected number of characters in string"); } Symbol* arr_sig = create_temporary_symbol( @@ -3032,7 +3105,7 @@ void ClassVerifier::verify_aload(u2 index, StackMapFrame* current_frame, TRAPS) { VerificationType type = current_frame->get_local( - index, VerificationType::reference_check(), CHECK_VERIFY(this)); + index, VerificationType::nonscalar_check(), CHECK_VERIFY(this)); current_frame->push_stack(type, CHECK_VERIFY(this)); } @@ -3069,7 +3142,7 @@ void ClassVerifier::verify_astore(u2 index, StackMapFrame* current_frame, TRAPS) { VerificationType type = current_frame->pop_stack( - VerificationType::reference_check(), CHECK_VERIFY(this)); + VerificationType::nonscalar_check(), CHECK_VERIFY(this)); current_frame->set_local(index, type, CHECK_VERIFY(this)); }