diff options
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 432 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.h | 26 |
2 files changed, 221 insertions, 237 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 2be47d17d0..a10c7cb895 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2175,91 +2175,95 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { 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: @@ -2686,34 +2690,34 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { // 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_BOOLEAN_QUICK: - VerifyIPutQuick(inst, reg_types_.Boolean(), true); + VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true); break; case Instruction::IPUT_BYTE_QUICK: - VerifyIPutQuick(inst, reg_types_.Byte(), true); + VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true); break; case Instruction::IPUT_CHAR_QUICK: - VerifyIPutQuick(inst, reg_types_.Char(), true); + VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true); break; case Instruction::IPUT_SHORT_QUICK: - VerifyIPutQuick(inst, reg_types_.Short(), true); + VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), 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: { @@ -3795,8 +3799,9 @@ mirror::ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int } } -void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_type, - bool is_primitive, bool is_static) { +template <MethodVerifier::FieldAccessType kAccType> +void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const 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) { @@ -3804,9 +3809,20 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty } else { const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c()); field = GetInstanceField(object_type, field_idx); + if (UNLIKELY(have_pending_hard_failure_)) { + return; + } } const 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; + } + } + mirror::Class* field_type_class; { StackHandleScope<1> hs(self_); @@ -3828,88 +3844,56 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty } 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; - } - } 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(this, vregA, reg_types_.Conflict()); - return; - } - } - if (!field_type->IsLowHalf()) { - work_line_->SetRegisterType(this, vregA, *field_type); - } else { - work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(®_types_)); - } -} - -void MethodVerifier::VerifyISPut(const Instruction* inst, const 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 { - const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c()); - field = GetInstanceField(object_type, field_idx); - } - const 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; + 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(this, vregA, *field_type); } - mirror::Class* field_type_class; - { - StackHandleScope<1> hs(self_); - HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field)); - FieldHelper fh(h_field); - field_type_class = fh.GetType(can_load_classes_); + } 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 { + 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(this, vregA, reg_types_.Conflict()); + return; + } } - if (field_type_class != nullptr) { - field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class, - field_type_class->CannotBeAssignedFromOtherTypes()); + if (!field_type->IsLowHalf()) { + work_line_->SetRegisterType(this, vregA, *field_type); } else { - DCHECK(!can_load_classes_ || self_->IsExceptionPending()); - self_->ClearException(); + work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(®_types_)); } - } - 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(GetClassLoader(), 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); } 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(this, vregA, *field_type); + LOG(FATAL) << "Unexpected case."; } } @@ -3940,131 +3924,137 @@ mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, return f; } -void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type, - bool is_primitive) { +template <MethodVerifier::FieldAccessType kAccType> +void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const 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(self_); - HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field)); - FieldHelper fh(h_field); - field_type_class = fh.GetType(can_load_classes_); + + // 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; + } } + + // Get the field type. const RegType* field_type; - if (field_type_class != nullptr) { - field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class, - field_type_class->CannotBeAssignedFromOtherTypes()); - } else { - 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 + { + 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 { - // 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; + Thread* self = Thread::Current(); + DCHECK(!can_load_classes_ || self->IsExceptionPending()); + self->ClearException(); + field_type = ®_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(), + field->GetTypeDescriptor(), false); } - } 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(this, vregA, reg_types_.Conflict()); + if (field_type == nullptr) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name(); return; } } - if (!field_type->IsLowHalf()) { - work_line_->SetRegisterType(this, vregA, *field_type); - } else { - work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(®_types_)); - } -} -void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const 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(); - const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false); - 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; - } - } 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; - const RegType& value_type = work_line_->GetRegisterType(this, 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(); + 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; + const RegType& value_type = work_line_->GetRegisterType(this, 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 { - instruction_compatible = false; // reference field with primitive store - value_compatible = false; // unused + 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(this, vregA, *field_type); } - 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; + } 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(this, vregA, reg_types_.Conflict()); + 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; + if (!field_type->IsLowHalf()) { + work_line_->SetRegisterType(this, vregA, *field_type); + } else { + work_line_->SetRegisterTypeWide(this, 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(this, vregA, field_type); + LOG(FATAL) << "Unexpected case."; } } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 9f5efe851f..357acf0e5c 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -511,14 +511,14 @@ class MethodVerifier { // 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, const 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, const 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, const 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 @@ -526,14 +526,8 @@ class MethodVerifier { 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, const RegType& insn_type, - bool is_primitive) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - // Perform verification of an iput-quick instruction. - void VerifyIPutQuick(const Instruction* inst, const RegType& insn_type, - bool is_primitive) + template <FieldAccessType kAccType> + void VerifyQuickFieldAccess(const Instruction* inst, const 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 |