Handle a potential race when verifying dex files in the background.
In case the runtime has verified a class already, explicitly still
perform another verification in order to get the verifier_deps
populated.
Test: test.py
Change-Id: I17dcec9545dab1b0cae170b584cd091f00145344
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 82b644d..0f5f139 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -148,6 +148,7 @@
#include "transaction.h"
#include "vdex_file.h"
#include "verifier/class_verifier.h"
+#include "verifier/verifier_deps.h"
#include "well_known_classes.h"
#include "interpreter/interpreter_mterp_impl.h"
@@ -4560,6 +4561,22 @@
// Don't attempt to re-verify if already verified.
if (klass->IsVerified()) {
EnsureSkipAccessChecksMethods(klass, image_pointer_size_);
+ if (verifier_deps != nullptr &&
+ verifier_deps->ContainsDexFile(klass->GetDexFile()) &&
+ !verifier_deps->HasRecordedVerifiedStatus(klass->GetDexFile(), *klass->GetClassDef()) &&
+ !Runtime::Current()->IsAotCompiler()) {
+ // If the klass is verified, but `verifier_deps` did not record it, this
+ // means we are running background verification of a secondary dex file.
+ // Re-run the verifier to populate `verifier_deps`.
+ // No need to run the verification when running on the AOT Compiler, as
+ // the driver handles those multithreaded cases already.
+ std::string error_msg;
+ verifier::FailureKind failure =
+ PerformClassVerification(self, verifier_deps, klass, log_level, &error_msg);
+ // We could have soft failures, so just check that we don't have a hard
+ // failure.
+ DCHECK_NE(failure, verifier::FailureKind::kHardFailure) << error_msg;
+ }
return verifier::FailureKind::kNoFailure;
}
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index c9128f8..c416c3d 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -308,6 +308,13 @@
dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)] = true;
}
+bool VerifierDeps::HasRecordedVerifiedStatus(const DexFile& dex_file,
+ const dex::ClassDef& class_def) {
+ DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
+ DCHECK_EQ(dex_deps->verified_classes_.size(), dex_file.NumClassDefs());
+ return dex_deps->verified_classes_[dex_file.GetIndexForClassDef(class_def)];
+}
+
void VerifierDeps::MaybeRecordAssignability(VerifierDeps* verifier_deps,
const DexFile& dex_file,
const dex::ClassDef& class_def,
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 2e8ef4e..0c448f8 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -124,10 +124,18 @@
return GetDexFileDeps(dex_file)->verified_classes_;
}
+ // Whether this `verifier_deps` has recorded that the given class is verified.
+ bool HasRecordedVerifiedStatus(const DexFile& dex_file, const dex::ClassDef& class_def)
+ REQUIRES(!Locks::verifier_deps_lock_);
+
bool OutputOnly() const {
return output_only_;
}
+ bool ContainsDexFile(const DexFile& dex_file) const {
+ return GetDexFileDeps(dex_file) != nullptr;
+ }
+
// Parses raw VerifierDeps data to extract bitvectors of which class def indices
// were verified or not. The given `dex_files` must match the order and count of
// dex files used to create the VerifierDeps.