< prev index next > src/hotspot/share/classfile/verifier.cpp
Print this page
#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" {
Symbol* name = klass->name();
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
name != vmSymbols::java_lang_Object() &&
name != vmSymbols::java_lang_Class() &&
name != vmSymbols::java_lang_String() &&
name != vmSymbols::java_lang_Throwable() &&
Symbol* name = klass->name();
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 bootstrapping
name != vmSymbols::java_lang_Object() &&
name != vmSymbols::java_lang_Class() &&
name != vmSymbols::java_lang_String() &&
name != vmSymbols::java_lang_Throwable() &&
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");
}
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.
"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() &&
current_frame.flag_this_uninit()) {
verify_error(ErrorContext::bad_code(bci),
"Constructor must call super() or this() "
"before return");
return;
"Method expects a return value");
return;
}
// Make sure "this" has been initialized if current method is an
// <init>.
! 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;
&bcs, ¤t_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, ¤t_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, ¤t_frame, (bci >= ex_min && bci < ex_max),
! &this_uninit, return_type, 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));
&bcs, ¤t_frame, cp, false, CHECK_VERIFY(this));
no_control_flow = false; break;
case Bytecodes::_invokevirtual :
case Bytecodes::_invokespecial :
case Bytecodes::_invokestatic :
case Bytecodes::_invokeinterface :
case Bytecodes::_invokedynamic :
verify_invoke_instructions(
&bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max),
! &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));
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(
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));
current_frame.push_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
no_control_flow = false; break;
}
case Bytecodes::_monitorenter :
! 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));
// 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;
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_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));
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_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));
// 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())) {
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];
// 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())) {
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];
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
// 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();
}
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,
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));
! // Field initialization is allowed before the superclass
// initializer, if the field is defined within the current class.
fieldDescriptor fd;
! 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,
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,
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;
return false;
}
void ClassVerifier::verify_invoke_instructions(
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
! 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;
// Method signature was checked in ClassFileParser.
assert(SignatureVerifier::is_valid_method_signature(method_sig),
"Invalid method signature");
! // Get referenced class type
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",
// Method signature was checked in ClassFileParser.
assert(SignatureVerifier::is_valid_method_signature(method_sig),
"Invalid method signature");
! // 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",
return;
}
}
if (method_name->char_at(0) == JVM_SIGNATURE_SPECIAL) {
! // Make sure <init> can only be invoked by invokespecial
if (opcode != Bytecodes::_invokespecial ||
! 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()))) {
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) {
return;
}
}
if (method_name->char_at(0) == JVM_SIGNATURE_SPECIAL) {
! // Make sure:
+ // <init> can only be invoked by invokespecial.
if (opcode != Bytecodes::_invokespecial ||
! 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()))) { // 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) {
}
// 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 */
verify_error(ErrorContext::bad_code(bci),
"Return type must be void in <init> method");
return;
}
}
// 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()) {
! // 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 >