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/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 6538925..5c097da 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -624,7 +624,7 @@
}
TEST_F(VerifierDepsTest, ConstClass_Unresolved) {
- ASSERT_TRUE(VerifyMethod("ConstClass_Unresolved"));
+ ASSERT_FALSE(VerifyMethod("ConstClass_Unresolved"));
ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
}
@@ -634,7 +634,7 @@
}
TEST_F(VerifierDepsTest, CheckCast_Unresolved) {
- ASSERT_TRUE(VerifyMethod("CheckCast_Unresolved"));
+ ASSERT_FALSE(VerifyMethod("CheckCast_Unresolved"));
ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
}
@@ -644,7 +644,7 @@
}
TEST_F(VerifierDepsTest, InstanceOf_Unresolved) {
- ASSERT_TRUE(VerifyMethod("InstanceOf_Unresolved"));
+ ASSERT_FALSE(VerifyMethod("InstanceOf_Unresolved"));
ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
}
@@ -654,12 +654,12 @@
}
TEST_F(VerifierDepsTest, NewInstance_Unresolved) {
- ASSERT_TRUE(VerifyMethod("NewInstance_Unresolved"));
+ ASSERT_FALSE(VerifyMethod("NewInstance_Unresolved"));
ASSERT_TRUE(HasClass("LUnresolvedClass;", false));
}
TEST_F(VerifierDepsTest, NewArray_Unresolved) {
- ASSERT_TRUE(VerifyMethod("NewArray_Unresolved"));
+ ASSERT_FALSE(VerifyMethod("NewArray_Unresolved"));
ASSERT_TRUE(HasClass("[LUnresolvedClass;", false));
}
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();
diff --git a/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali b/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali
index 882f0e9..2604472 100644
--- a/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali
+++ b/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali
@@ -23,7 +23,7 @@
.line 23
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
# Get an unresolvable instance (abstract class)
- invoke-static {}, LAbstract;->getUnresolvedInstance()Lother/thing/Foo;
+ invoke-static {}, LUnresolved;->getUnresolvedInstance()Lother/thing/Foo;
move-result-object v0
const-string v1, "1"
const-string v2, "2"