ART: Don't check access for method parameters
Rename ResolveClassAndCheckAccess to ResolveClass and add a CheckAccess
template parameter. Do not check access when checking the signature of
the method to be verified. A parameter itself is not an access and would
not trigger an IllegalAccessError. So only check on actual usage.
Bug: 64681719
Test: m test-art-host
Change-Id: I00aa37f5fb097b37e267bd4332638fa3092b4fe9
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index 6c832e3..9bb875c 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -77,7 +77,7 @@
inline const RegType& MethodVerifier::ResolveCheckedClass(dex::TypeIndex class_idx) {
DCHECK(!HasFailures());
- const RegType& result = ResolveClassAndCheckAccess(class_idx);
+ const RegType& result = ResolveClass<CheckAccess::kYes>(class_idx);
DCHECK(!HasFailures());
return result;
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index cf4a6e0..f1b1080 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1765,7 +1765,9 @@
// it's effectively considered initialized the instant we reach here (in the sense that we
// can return without doing anything or call virtual methods).
{
- const RegType& reg_type = ResolveClassAndCheckAccess(iterator.GetTypeIdx());
+ // Note: don't check access. No error would be thrown for declaring or passing an
+ // inaccessible class. Only actual accesses to fields or methods will.
+ const RegType& reg_type = ResolveClass<CheckAccess::kNo>(iterator.GetTypeIdx());
if (!reg_type.IsNonZeroReferenceTypes()) {
DCHECK(HasFailures());
return false;
@@ -2322,7 +2324,7 @@
case Instruction::CONST_CLASS: {
// Get type from instruction if unresolved then we need an access check
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
+ const RegType& res_type = ResolveClass<CheckAccess::kYes>(dex::TypeIndex(inst->VRegB_21c()));
// Register holds class, ie its type is class, on error it will hold Conflict.
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), res_type.IsConflict() ? res_type
@@ -2393,7 +2395,7 @@
*/
const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
const dex::TypeIndex type_idx((is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c());
- const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
+ const RegType& res_type = ResolveClass<CheckAccess::kYes>(type_idx);
if (res_type.IsConflict()) {
// If this is a primitive type, fail HARD.
ObjPtr<mirror::Class> klass =
@@ -2463,7 +2465,7 @@
break;
}
case Instruction::NEW_INSTANCE: {
- const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
+ const RegType& res_type = ResolveClass<CheckAccess::kYes>(dex::TypeIndex(inst->VRegB_21c()));
if (res_type.IsConflict()) {
DCHECK_NE(failures_.size(), 0U);
break; // bad class
@@ -2675,7 +2677,7 @@
// ensure that subsequent merges don't lose type information - such as becoming an
// interface from a class that would lose information relevant to field checks.
const RegType& orig_type = work_line_->GetRegisterType(this, instance_of_inst->VRegB_22c());
- const RegType& cast_type = ResolveClassAndCheckAccess(
+ const RegType& cast_type = ResolveClass<CheckAccess::kYes>(
dex::TypeIndex(instance_of_inst->VRegC_22c()));
if (!orig_type.Equals(cast_type) &&
@@ -3723,7 +3725,8 @@
return klass->IsInstantiable() || klass->IsPrimitive();
}
-const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) {
+template <MethodVerifier::CheckAccess C>
+const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
mirror::Class* klass = can_load_classes_
? Runtime::Current()->GetClassLinker()->ResolveType(
*dex_file_, class_idx, dex_cache_, class_loader_)
@@ -3763,7 +3766,7 @@
// 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 (result->IsNonZeroReferenceTypes() && !result->IsUnresolvedTypes()) {
+ if (C == CheckAccess::kYes && result->IsNonZeroReferenceTypes() && !result->IsUnresolvedTypes()) {
const RegType& referrer = GetDeclaringClass();
if (!referrer.IsUnresolvedTypes() && !referrer.CanAccess(*result)) {
Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
@@ -3785,7 +3788,8 @@
if (!iterator.GetHandlerTypeIndex().IsValid()) {
common_super = ®_types_.JavaLangThrowable(false);
} else {
- const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
+ const RegType& exception =
+ ResolveClass<CheckAccess::kYes>(iterator.GetHandlerTypeIndex());
if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(exception, this)) {
DCHECK(!exception.IsUninitializedTypes()); // Comes from dex, shouldn't be uninit.
if (exception.IsUnresolvedTypes()) {
@@ -3827,7 +3831,7 @@
ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
uint32_t dex_method_idx, MethodType method_type) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
- const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
+ const RegType& klass_type = ResolveClass<CheckAccess::kYes>(method_id.class_idx_);
if (klass_type.IsConflict()) {
std::string append(" in attempt to access method ");
append += dex_file_->GetMethodName(method_id);
@@ -4598,7 +4602,7 @@
DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
type_idx = dex::TypeIndex(inst->VRegB_3rc());
}
- const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
+ const RegType& res_type = ResolveClass<CheckAccess::kYes>(type_idx);
if (res_type.IsConflict()) { // bad class
DCHECK_NE(failures_.size(), 0U);
} else {
@@ -4812,7 +4816,7 @@
ArtField* MethodVerifier::GetStaticField(int field_idx) {
const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
// Check access to class
- const RegType& klass_type = ResolveClassAndCheckAccess(field_id.class_idx_);
+ const RegType& klass_type = ResolveClass<CheckAccess::kYes>(field_id.class_idx_);
if (klass_type.IsConflict()) { // bad class
AppendToLastFailMessage(StringPrintf(" in attempt to access static field %d (%s) in %s",
field_idx, dex_file_->GetFieldName(field_id),
@@ -4850,7 +4854,7 @@
ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_idx) {
const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
// Check access to class.
- const RegType& klass_type = ResolveClassAndCheckAccess(field_id.class_idx_);
+ const RegType& klass_type = ResolveClass<CheckAccess::kYes>(field_id.class_idx_);
if (klass_type.IsConflict()) {
AppendToLastFailMessage(StringPrintf(" in attempt to access instance field %d (%s) in %s",
field_idx, dex_file_->GetFieldName(field_id),
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index ea8729c..da4102a 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -576,9 +576,14 @@
void VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type, bool is_primitive)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolves a class based on an index and performs access checks to ensure the referrer can
- // access the resolved class.
- const RegType& ResolveClassAndCheckAccess(dex::TypeIndex class_idx)
+ enum class CheckAccess { // private.
+ kYes,
+ kNo,
+ };
+ // Resolves a class based on an index and, if C is kYes, performs access checks to ensure
+ // the referrer can access the resolved class.
+ template <CheckAccess C>
+ const RegType& ResolveClass(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
/*