summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/verifier/method_verifier.cc71
1 files changed, 38 insertions, 33 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c32b2f0fca..1dd4bde4e8 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -165,13 +165,27 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
api_level_(api_level == 0 ? std::numeric_limits<uint32_t>::max() : api_level) {
}
- void UninstantiableError(const char* descriptor) {
- Fail(VerifyError::VERIFY_ERROR_NO_CLASS) << "Could not create precise reference for "
- << "non-instantiable klass " << descriptor;
+ void FinalAbstractClassError(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Note: We reuse NO_CLASS as the instruction we're checking shall throw an exception at
+ // runtime if executed. A final abstract class shall fail verification, so no instances can
+ // be created and therefore instance field or method access can be reached only for a null
+ // reference and throw NPE. All other instructions where we check for final abstract class
+ // shall throw `VerifyError`. (But we can also hit OOME/SOE while creating the exception.)
+ std::string temp;
+ const char* descriptor = klass->GetDescriptor(&temp);
+ Fail(VerifyError::VERIFY_ERROR_NO_CLASS)
+ << "Final abstract class used in a context that requires a verified class: " << descriptor;
}
- static bool IsInstantiableOrPrimitive(ObjPtr<mirror::Class> klass)
+
+ void CheckForFinalAbstractClass(ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return klass->IsInstantiable() || klass->IsPrimitive();
+ if (UNLIKELY(klass->IsFinal() &&
+ klass->IsAbstract() &&
+ !klass->IsInterface() &&
+ !klass->IsPrimitive() &&
+ !klass->IsArrayClass())) {
+ FinalAbstractClassError(klass);
+ }
}
// Is the method being verified a constructor? See the comment on the field.
@@ -671,22 +685,6 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
const RegType& DetermineCat1Constant(int32_t value)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Try to create a register type from the given class. In case a precise type is requested, but
- // the class is not instantiable, a soft error (of type NO_CLASS) will be enqueued and a
- // non-precise reference will be returned.
- // Note: we reuse NO_CLASS as this will throw an exception at runtime, when the failing class is
- // actually touched.
- const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass, bool precise)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(klass != nullptr);
- if (precise && !klass->IsInstantiable() && !klass->IsPrimitive()) {
- Fail(VerifyError::VERIFY_ERROR_NO_CLASS) << "Could not create precise reference for "
- << "non-instantiable klass " << descriptor;
- precise = false;
- }
- return reg_types_.FromClass(descriptor, klass, precise);
- }
-
ALWAYS_INLINE bool FailOrAbort(bool condition, const char* error_msg, uint32_t work_insn_idx);
ALWAYS_INLINE InstructionFlags& GetModifiableInstructionFlags(size_t index) {
@@ -3557,11 +3555,6 @@ const RegType& MethodVerifier<kVerifierDebug>::ResolveClass(dex::TypeIndex class
const RegType* result = nullptr;
if (klass != nullptr) {
bool precise = klass->CannotBeAssignedFromOtherTypes();
- if (precise && !IsInstantiableOrPrimitive(klass)) {
- const char* descriptor = dex_file_->GetTypeDescriptor(class_idx);
- UninstantiableError(descriptor);
- precise = false;
- }
result = reg_types_.FindClass(klass, precise);
if (result == nullptr) {
const char* descriptor = dex_file_->GetTypeDescriptor(class_idx);
@@ -3682,6 +3675,8 @@ bool MethodVerifier<kVerifierDebug>::HandleMoveException(const Instruction* inst
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to find exception handler";
return std::make_pair(true, &reg_types_.Conflict());
}
+ DCHECK(common_super->HasClass());
+ CheckForFinalAbstractClass(common_super->GetClass());
return std::make_pair(true, common_super);
};
auto result = caught_exc_type_fn();
@@ -3887,8 +3882,8 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator(
if (res_method != nullptr && !res_method->IsMiranda()) {
ObjPtr<mirror::Class> klass = res_method->GetDeclaringClass();
std::string temp;
- res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
- klass->CannotBeAssignedFromOtherTypes());
+ res_method_class = &reg_types_.FromClass(
+ klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
} else {
const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
@@ -4133,16 +4128,25 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgs(
}
}
+ ArtMethod* verified_method;
if (UNLIKELY(method_type == METHOD_POLYMORPHIC)) {
// Process the signature of the calling site that is invoking the method handle.
dex::ProtoIndex proto_idx(inst->VRegH());
DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(proto_idx));
- return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ verified_method =
+ VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
} else {
// Process the target method's signature.
MethodParamListDescriptorIterator it(res_method);
- return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ verified_method =
+ VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ }
+
+ if (verified_method != nullptr && !verified_method->GetDeclaringClass()->IsInterface()) {
+ CheckForFinalAbstractClass(res_method->GetDeclaringClass());
}
+
+ return verified_method;
}
template <bool kVerifierDebug>
@@ -4546,10 +4550,10 @@ ArtField* MethodVerifier<kVerifierDebug>::GetInstanceField(const RegType& obj_ty
// Cannot infer and check type, however, access will cause null pointer exception.
// Fall through into a few last soft failure checks below.
} else {
- std::string temp;
ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
- const RegType& field_klass =
- FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
+ std::string temp;
+ const RegType& field_klass = reg_types_.FromClass(
+ klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
if (obj_type.IsUninitializedTypes()) {
// Field accesses through uninitialized references are only allowable for constructors where
// the field is declared in this class.
@@ -4649,6 +4653,7 @@ void MethodVerifier<kVerifierDebug>::VerifyISFieldAccess(const Instruction* inst
}
}
if (field != nullptr) {
+ CheckForFinalAbstractClass(field->GetDeclaringClass());
if (kAccType == FieldAccessType::kAccPut) {
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << field->PrettyField()