Add unresolved types in verifier deps.
We need to record all assignability checks that the verifier does, so we
reproduce them at runtime.
We ignore those assignability checks for now when validating a vdex file
as the class that uses the unresolved types will be marked as soft fail.
Test: test.py
Bug: 112676029
Change-Id: I21697e976ce56d3905576407b6326863915cc271
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index 3c7ad03..31426f8 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -121,6 +121,11 @@
}
return result;
} else {
+ // For unresolved types, we don't know if they are assignable, and the
+ // verifier will continue assuming they are. We need to record that.
+ if (verifier != nullptr) {
+ VerifierDeps::MaybeRecordAssignability(verifier->GetDexFile(), lhs, rhs);
+ }
// Unresolved types are only assignable for null and equality.
// Null cannot be the left-hand side.
return false;
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index f634645..e8a7a80 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -1142,6 +1142,8 @@
std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
+ const RegTypeCache* GetRegTypeCache() const { return reg_type_cache_; }
+
private:
void CheckInvariants() const REQUIRES_SHARED(Locks::mutator_lock_) override;
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index 036719d..a3f3ff8 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -17,6 +17,7 @@
#ifndef ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_
#define ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_
+#include "base/bit_vector-inl.h"
#include "class_linker.h"
#include "class_root-inl.h"
#include "mirror/class-inl.h"
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 1df5c02..5f31473 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -31,6 +31,8 @@
#include "mirror/class_loader.h"
#include "oat_file.h"
#include "obj_ptr-inl.h"
+#include "reg_type.h"
+#include "reg_type_cache-inl.h"
#include "runtime.h"
namespace art {
@@ -352,6 +354,36 @@
dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
}
+void VerifierDeps::AddAssignability(const DexFile& dex_file,
+ const RegType& destination,
+ const RegType& source) {
+ DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
+ if (dex_deps == nullptr) {
+ // This invocation is from verification of a DEX file which is not being compiled.
+ return;
+ }
+
+ CHECK(destination.IsUnresolvedReference() || destination.HasClass());
+ CHECK(!destination.IsUnresolvedMergedReference());
+
+ if (source.IsUnresolvedReference() || source.HasClass()) {
+ // Get string IDs for both descriptors and store in the appropriate set.
+ dex::StringIndex destination_id =
+ GetIdFromString(dex_file, std::string(destination.GetDescriptor()));
+ dex::StringIndex source_id = GetIdFromString(dex_file, std::string(source.GetDescriptor()));
+ dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
+ } else if (source.IsZeroOrNull()) {
+ // Nothing to record, null is always assignable.
+ } else {
+ CHECK(source.IsUnresolvedMergedReference()) << source.Dump();
+ const UnresolvedMergedType& merge = *down_cast<const UnresolvedMergedType*>(&source);
+ AddAssignability(dex_file, destination, merge.GetResolvedPart());
+ for (uint32_t idx : merge.GetUnresolvedTypes().Indexes()) {
+ AddAssignability(dex_file, destination, merge.GetRegTypeCache()->GetFromId(idx));
+ }
+ }
+}
+
void VerifierDeps::MaybeRecordClassRedefinition(const DexFile& dex_file,
const dex::ClassDef& class_def) {
VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
@@ -390,6 +422,15 @@
}
}
+void VerifierDeps::MaybeRecordAssignability(const DexFile& dex_file,
+ const RegType& destination,
+ const RegType& source) {
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddAssignability(dex_file, destination, source);
+ }
+}
+
namespace {
template<typename T> inline uint32_t Encode(T in);
@@ -753,14 +794,11 @@
source.Assign(
FindClassAndClearException(class_linker, self, source_desc.c_str(), class_loader));
- if (destination == nullptr) {
- *error_msg = "Could not resolve class " + destination_desc;
- return false;
- }
-
- if (source == nullptr) {
- *error_msg = "Could not resolve class " + source_desc;
- return false;
+ if (destination == nullptr || source == nullptr) {
+ // We currently don't use assignability information for unresolved
+ // types, as the status of the class using unresolved types will be soft
+ // fail in the vdex.
+ continue;
}
DCHECK(destination->IsResolved() && source->IsResolved());
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index b11ccb6..91087b3 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -44,6 +44,8 @@
namespace verifier {
+class RegType;
+
// Verification dependencies collector class used by the MethodVerifier to record
// resolution outcomes and type assignability tests of classes/methods/fields
// not present in the set of compiled DEX files, that is classes/methods/fields
@@ -93,6 +95,14 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
+ // Record that `source` is assignable to `destination`. `dex_file` is the
+ // owner of the method for which MethodVerifier performed the assignability test.
+ static void MaybeRecordAssignability(const DexFile& dex_file,
+ const RegType& destination,
+ const RegType& source)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::verifier_deps_lock_);
+
// Serialize the recorded dependencies and store the data into `buffer`.
// `dex_files` provides the order of the dex files in which the dependencies
// should be emitted.
@@ -213,6 +223,11 @@
ObjPtr<mirror::Class> source)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void AddAssignability(const DexFile& dex_file,
+ const RegType& destination,
+ const RegType& source)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
bool Equals(const VerifierDeps& rhs) const;
// Verify `dex_file` according to the `deps`, that is going over each