Merge "ART: Fix possible soft+hard failure in verifier" into lmp-mr1-dev
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4897381..c88a295 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2117,91 +2117,95 @@
break;
case Instruction::IGET_BOOLEAN:
- VerifyISGet(inst, reg_types_.Boolean(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IGET_BYTE:
- VerifyISGet(inst, reg_types_.Byte(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IGET_CHAR:
- VerifyISGet(inst, reg_types_.Char(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, false);
break;
case Instruction::IGET_SHORT:
- VerifyISGet(inst, reg_types_.Short(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, false);
break;
case Instruction::IGET:
- VerifyISGet(inst, reg_types_.Integer(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IGET_WIDE:
- VerifyISGet(inst, reg_types_.LongLo(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IGET_OBJECT:
- VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+ false);
break;
case Instruction::IPUT_BOOLEAN:
- VerifyISPut(inst, reg_types_.Boolean(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IPUT_BYTE:
- VerifyISPut(inst, reg_types_.Byte(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IPUT_CHAR:
- VerifyISPut(inst, reg_types_.Char(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, false);
break;
case Instruction::IPUT_SHORT:
- VerifyISPut(inst, reg_types_.Short(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, false);
break;
case Instruction::IPUT:
- VerifyISPut(inst, reg_types_.Integer(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IPUT_WIDE:
- VerifyISPut(inst, reg_types_.LongLo(), true, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IPUT_OBJECT:
- VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+ false);
break;
case Instruction::SGET_BOOLEAN:
- VerifyISGet(inst, reg_types_.Boolean(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, true);
break;
case Instruction::SGET_BYTE:
- VerifyISGet(inst, reg_types_.Byte(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, true);
break;
case Instruction::SGET_CHAR:
- VerifyISGet(inst, reg_types_.Char(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, true);
break;
case Instruction::SGET_SHORT:
- VerifyISGet(inst, reg_types_.Short(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, true);
break;
case Instruction::SGET:
- VerifyISGet(inst, reg_types_.Integer(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, true);
break;
case Instruction::SGET_WIDE:
- VerifyISGet(inst, reg_types_.LongLo(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, true);
break;
case Instruction::SGET_OBJECT:
- VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
+ VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+ true);
break;
case Instruction::SPUT_BOOLEAN:
- VerifyISPut(inst, reg_types_.Boolean(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, true);
break;
case Instruction::SPUT_BYTE:
- VerifyISPut(inst, reg_types_.Byte(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, true);
break;
case Instruction::SPUT_CHAR:
- VerifyISPut(inst, reg_types_.Char(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, true);
break;
case Instruction::SPUT_SHORT:
- VerifyISPut(inst, reg_types_.Short(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, true);
break;
case Instruction::SPUT:
- VerifyISPut(inst, reg_types_.Integer(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, true);
break;
case Instruction::SPUT_WIDE:
- VerifyISPut(inst, reg_types_.LongLo(), true, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, true);
break;
case Instruction::SPUT_OBJECT:
- VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
+ VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+ true);
break;
case Instruction::INVOKE_VIRTUAL:
@@ -2645,22 +2649,22 @@
// As such they use Class*/Field*/AbstractMethod* as these offsets only have
// meaning if the class linking and resolution were successful.
case Instruction::IGET_QUICK:
- VerifyIGetQuick(inst, reg_types_.Integer(), true);
+ VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
break;
case Instruction::IGET_WIDE_QUICK:
- VerifyIGetQuick(inst, reg_types_.LongLo(), true);
+ VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true);
break;
case Instruction::IGET_OBJECT_QUICK:
- VerifyIGetQuick(inst, reg_types_.JavaLangObject(false), false);
+ VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false);
break;
case Instruction::IPUT_QUICK:
- VerifyIPutQuick(inst, reg_types_.Integer(), true);
+ VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true);
break;
case Instruction::IPUT_WIDE_QUICK:
- VerifyIPutQuick(inst, reg_types_.LongLo(), true);
+ VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true);
break;
case Instruction::IPUT_OBJECT_QUICK:
- VerifyIPutQuick(inst, reg_types_.JavaLangObject(false), false);
+ VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false);
break;
case Instruction::INVOKE_VIRTUAL_QUICK:
case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -3747,8 +3751,9 @@
}
}
-void MethodVerifier::VerifyISGet(const Instruction* inst, RegType& insn_type,
- bool is_primitive, bool is_static) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, RegType& insn_type,
+ bool is_primitive, bool is_static) {
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
mirror::ArtField* field;
if (is_static) {
@@ -3756,9 +3761,20 @@
} else {
RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
field = GetInstanceField(object_type, field_idx);
+ if (UNLIKELY(have_pending_hard_failure_)) {
+ return;
+ }
}
RegType* field_type = nullptr;
if (field != nullptr) {
+ if (kAccType == FieldAccessType::kAccPut) {
+ if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
+ Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
+ << " from other class " << GetDeclaringClass();
+ return;
+ }
+ }
+
Thread* self = Thread::Current();
mirror::Class* field_type_class;
{
@@ -3781,89 +3797,56 @@
}
DCHECK(field_type != nullptr);
const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
- if (is_primitive) {
- if (field_type->Equals(insn_type) ||
- (field_type->IsFloat() && insn_type.IsInteger()) ||
- (field_type->IsDouble() && insn_type.IsLong())) {
- // expected that read is of the correct primitive type or that int reads are reading
- // floats or long reads are reading doubles
+ static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+ "Unexpected third access type");
+ if (kAccType == FieldAccessType::kAccPut) {
+ // sput or iput.
+ if (is_primitive) {
+ VerifyPrimitivePut(*field_type, insn_type, vregA);
} else {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << *field_type << "' in get";
- return;
+ if (!insn_type.IsAssignableFrom(*field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << *field_type
+ << "' in put-object";
+ return;
+ }
+ work_line_->VerifyRegisterType(vregA, *field_type);
}
- } else {
- if (!insn_type.IsAssignableFrom(*field_type)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << *field_type
- << "' in Get-object";
- work_line_->SetRegisterType(vregA, reg_types_.Conflict());
- return;
- }
- }
- if (!field_type->IsLowHalf()) {
- work_line_->SetRegisterType(vregA, *field_type);
- } else {
- work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_));
- }
-}
-
-void MethodVerifier::VerifyISPut(const Instruction* inst, RegType& insn_type,
- bool is_primitive, bool is_static) {
- uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
- mirror::ArtField* field;
- if (is_static) {
- field = GetStaticField(field_idx);
- } else {
- RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
- field = GetInstanceField(object_type, field_idx);
- }
- RegType* field_type = nullptr;
- if (field != nullptr) {
- if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
- Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
- << " from other class " << GetDeclaringClass();
- return;
- }
- mirror::Class* field_type_class;
- {
- StackHandleScope<1> hs(Thread::Current());
- HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
- FieldHelper fh(h_field);
- field_type_class = fh.GetType(can_load_classes_);
- }
- if (field_type_class != nullptr) {
- field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
- field_type_class->CannotBeAssignedFromOtherTypes());
+ } else if (kAccType == FieldAccessType::kAccGet) {
+ // sget or iget.
+ if (is_primitive) {
+ if (field_type->Equals(insn_type) ||
+ (field_type->IsFloat() && insn_type.IsInteger()) ||
+ (field_type->IsDouble() && insn_type.IsLong())) {
+ // expected that read is of the correct primitive type or that int reads are reading
+ // floats or long reads are reading doubles
+ } else {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+ << " to be of type '" << insn_type
+ << "' but found type '" << *field_type << "' in get";
+ return;
+ }
} else {
- Thread* self = Thread::Current();
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
+ if (!insn_type.IsAssignableFrom(*field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << *field_type
+ << "' in get-object";
+ work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+ return;
+ }
}
- }
- if (field_type == nullptr) {
- const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
- const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
- field_type = ®_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
- }
- DCHECK(field_type != nullptr);
- const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
- if (is_primitive) {
- VerifyPrimitivePut(*field_type, insn_type, vregA);
+ if (!field_type->IsLowHalf()) {
+ work_line_->SetRegisterType(vregA, *field_type);
+ } else {
+ work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_));
+ }
} else {
- if (!insn_type.IsAssignableFrom(*field_type)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << *field_type
- << "' in put-object";
- return;
- }
- work_line_->VerifyRegisterType(vregA, *field_type);
+ LOG(FATAL) << "Unexpected case.";
}
}
@@ -3890,132 +3873,137 @@
return f;
}
-void MethodVerifier::VerifyIGetQuick(const Instruction* inst, RegType& insn_type,
- bool is_primitive) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, RegType& insn_type,
+ bool is_primitive) {
DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
- mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
- if (field == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
- return;
- }
- mirror::Class* field_type_class;
- {
- StackHandleScope<1> hs(Thread::Current());
- HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
- FieldHelper fh(h_field);
- field_type_class = fh.GetType(can_load_classes_);
- }
- RegType* field_type;
- if (field_type_class != nullptr) {
- field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
- field_type_class->CannotBeAssignedFromOtherTypes());
- } else {
- Thread* self = Thread::Current();
- DCHECK(!can_load_classes_ || self->IsExceptionPending());
- self->ClearException();
- field_type = ®_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
- field->GetTypeDescriptor(), false);
- }
- DCHECK(field_type != nullptr);
- const uint32_t vregA = inst->VRegA_22c();
- if (is_primitive) {
- if (field_type->Equals(insn_type) ||
- (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
- (field_type->IsDouble() && insn_type.IsLongTypes())) {
- // expected that read is of the correct primitive type or that int reads are reading
- // floats or long reads are reading doubles
- } else {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << *field_type << "' in Get";
- return;
- }
- } else {
- if (!insn_type.IsAssignableFrom(*field_type)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << *field_type
- << "' in get-object";
- work_line_->SetRegisterType(vregA, reg_types_.Conflict());
- return;
- }
- }
- if (!field_type->IsLowHalf()) {
- work_line_->SetRegisterType(vregA, *field_type);
- } else {
- work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_));
- }
-}
-void MethodVerifier::VerifyIPutQuick(const Instruction* inst, RegType& insn_type,
- bool is_primitive) {
- DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
if (field == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
return;
}
- const char* descriptor = field->GetTypeDescriptor();
- mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
- RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
- if (field != nullptr) {
+
+ // For an IPUT_QUICK, we now test for final flag of the field.
+ if (kAccType == FieldAccessType::kAccPut) {
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
<< " from other class " << GetDeclaringClass();
return;
}
}
- const uint32_t vregA = inst->VRegA_22c();
- if (is_primitive) {
- // Primitive field assignability rules are weaker than regular assignability rules
- bool instruction_compatible;
- bool value_compatible;
- RegType& value_type = work_line_->GetRegisterType(vregA);
- if (field_type.IsIntegralTypes()) {
- instruction_compatible = insn_type.IsIntegralTypes();
- value_compatible = value_type.IsIntegralTypes();
- } else if (field_type.IsFloat()) {
- instruction_compatible = insn_type.IsInteger(); // no [is]put-float, so expect [is]put-int
- value_compatible = value_type.IsFloatTypes();
- } else if (field_type.IsLong()) {
- instruction_compatible = insn_type.IsLong();
- value_compatible = value_type.IsLongTypes();
- } else if (field_type.IsDouble()) {
- instruction_compatible = insn_type.IsLong(); // no [is]put-double, so expect [is]put-long
- value_compatible = value_type.IsDoubleTypes();
+
+ // Get the field type.
+ RegType* field_type;
+ {
+ mirror::Class* field_type_class;
+ {
+ StackHandleScope<1> hs(Thread::Current());
+ HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
+ field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
+ }
+
+ if (field_type_class != nullptr) {
+ field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
+ field_type_class->CannotBeAssignedFromOtherTypes());
} else {
- instruction_compatible = false; // reference field with primitive store
- value_compatible = false; // unused
+ Thread* self = Thread::Current();
+ DCHECK(!can_load_classes_ || self->IsExceptionPending());
+ self->ClearException();
+ field_type = ®_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
+ field->GetTypeDescriptor(), false);
}
- if (!instruction_compatible) {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << field_type
- << "' in put";
+ if (field_type == nullptr) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name();
return;
}
- if (!value_compatible) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
- << " of type " << value_type
- << " but expected " << field_type
- << " for store to " << PrettyField(field) << " in put";
- return;
+ }
+
+ const uint32_t vregA = inst->VRegA_22c();
+ static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+ "Unexpected third access type");
+ if (kAccType == FieldAccessType::kAccPut) {
+ if (is_primitive) {
+ // Primitive field assignability rules are weaker than regular assignability rules
+ bool instruction_compatible;
+ bool value_compatible;
+ RegType& value_type = work_line_->GetRegisterType(vregA);
+ if (field_type->IsIntegralTypes()) {
+ instruction_compatible = insn_type.IsIntegralTypes();
+ value_compatible = value_type.IsIntegralTypes();
+ } else if (field_type->IsFloat()) {
+ instruction_compatible = insn_type.IsInteger(); // no [is]put-float, so expect [is]put-int
+ value_compatible = value_type.IsFloatTypes();
+ } else if (field_type->IsLong()) {
+ instruction_compatible = insn_type.IsLong();
+ value_compatible = value_type.IsLongTypes();
+ } else if (field_type->IsDouble()) {
+ instruction_compatible = insn_type.IsLong(); // no [is]put-double, so expect [is]put-long
+ value_compatible = value_type.IsDoubleTypes();
+ } else {
+ instruction_compatible = false; // reference field with primitive store
+ value_compatible = false; // unused
+ }
+ if (!instruction_compatible) {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+ << " to be of type '" << insn_type
+ << "' but found type '" << *field_type
+ << "' in put";
+ return;
+ }
+ if (!value_compatible) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
+ << " of type " << value_type
+ << " but expected " << *field_type
+ << " for store to " << PrettyField(field) << " in put";
+ return;
+ }
+ } else {
+ if (!insn_type.IsAssignableFrom(*field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << *field_type
+ << "' in put-object";
+ return;
+ }
+ work_line_->VerifyRegisterType(vregA, *field_type);
+ }
+ } else if (kAccType == FieldAccessType::kAccGet) {
+ if (is_primitive) {
+ if (field_type->Equals(insn_type) ||
+ (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
+ (field_type->IsDouble() && insn_type.IsLongTypes())) {
+ // expected that read is of the correct primitive type or that int reads are reading
+ // floats or long reads are reading doubles
+ } else {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+ << " to be of type '" << insn_type
+ << "' but found type '" << *field_type << "' in Get";
+ return;
+ }
+ } else {
+ if (!insn_type.IsAssignableFrom(*field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << *field_type
+ << "' in get-object";
+ work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+ return;
+ }
+ }
+ if (!field_type->IsLowHalf()) {
+ work_line_->SetRegisterType(vregA, *field_type);
+ } else {
+ work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_));
}
} else {
- if (!insn_type.IsAssignableFrom(field_type)) {
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
- << " to be compatible with type '" << insn_type
- << "' but found type '" << field_type
- << "' in put-object";
- return;
- }
- work_line_->VerifyRegisterType(vregA, field_type);
+ LOG(FATAL) << "Unexpected case.";
}
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 17713d2..d7dd4b8 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -506,14 +506,14 @@
// Lookup static field and fail for resolution violations
mirror::ArtField* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Perform verification of an iget or sget instruction.
- void VerifyISGet(const Instruction* inst, RegType& insn_type,
- bool is_primitive, bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // Perform verification of an iput or sput instruction.
- void VerifyISPut(const Instruction* inst, RegType& insn_type,
- bool is_primitive, bool is_static)
+ // Perform verification of an iget/sget/iput/sput instruction.
+ enum class FieldAccessType { // private
+ kAccGet,
+ kAccPut
+ };
+ template <FieldAccessType kAccType>
+ void VerifyISFieldAccess(const Instruction* inst, RegType& insn_type,
+ bool is_primitive, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns the access field of a quick field access (iget/iput-quick) or nullptr
@@ -521,14 +521,8 @@
mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Perform verification of an iget-quick instruction.
- void VerifyIGetQuick(const Instruction* inst, RegType& insn_type,
- bool is_primitive)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // Perform verification of an iput-quick instruction.
- void VerifyIPutQuick(const Instruction* inst, RegType& insn_type,
- bool is_primitive)
+ template <FieldAccessType kAccType>
+ void VerifyQuickFieldAccess(const Instruction* inst, RegType& insn_type, bool is_primitive)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolves a class based on an index and performs access checks to ensure the referrer can