ART: Redo verification on class resolution failure
During compile-time verification, when a class needs to be resolved
and access to that class checked, if we can't resolve the class,
do a conservative access check and post an ACCESS_CLASS failure, if
necessary. This will trigger a re-verification at runtime, when the
class should be available.
Fix an invoke-polymorphic test to not trigger dead code. Fix method
expectations in verifier_deps_test.
Bug: 64681719
Test: m test-art-host
Test: cts-tradefed run commandAndExit cts --m vm-tests-tf
Change-Id: I3639639476f6938e10df1b0dac4545fe841a6ad2
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f1b1080..9a87607 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3763,13 +3763,15 @@
// Record result of class resolution attempt.
VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass);
- // Check if access is allowed. Unresolved types use xxxWithAccessCheck to
- // check at runtime if access is allowed and so pass here. If result is
- // primitive, skip the access check.
- if (C == CheckAccess::kYes && result->IsNonZeroReferenceTypes() && !result->IsUnresolvedTypes()) {
+ // If requested, check if access is allowed. Unresolved types are included in this check, as the
+ // interpreter only tests whether access is allowed when a class is not pre-verified and runs in
+ // the access-checks interpreter. If result is primitive, skip the access check.
+ //
+ // Note: we do this for unresolved classes to trigger re-verification at runtime.
+ if (C == CheckAccess::kYes && result->IsNonZeroReferenceTypes()) {
const RegType& referrer = GetDeclaringClass();
- if (!referrer.IsUnresolvedTypes() && !referrer.CanAccess(*result)) {
- Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
+ if (!referrer.CanAccess(*result)) {
+ Fail(VERIFY_ERROR_ACCESS_CLASS) << "(possibly) illegal class access: '"
<< referrer << "' -> '" << *result << "'";
}
}
@@ -4824,6 +4826,9 @@
return nullptr;
}
if (klass_type.IsUnresolvedTypes()) {
+ // Accessibility checks depend on resolved fields.
+ DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty());
+
return nullptr; // Can't resolve Class so no more to do here, will do checking at runtime.
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -4862,6 +4867,9 @@
return nullptr;
}
if (klass_type.IsUnresolvedTypes()) {
+ // Accessibility checks depend on resolved fields.
+ DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty());
+
return nullptr; // Can't resolve Class so no more to do here
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();