summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_builder.cc
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2020-08-18 09:29:51 +0100
committerVladimir Marko <vmarko@google.com>2020-08-24 09:32:55 +0000
commitcfd65805a5b3b0437e355b8044a05ee6c9d352c5 (patch)
treec91f72b2fe4325cbbc21b6d4a889ea87a7c3608f /compiler/optimizing/instruction_builder.cc
parent095dc4611b8001861f8d0e621f9df704a933754a (diff)
Optimizing: Fix weak method access check.
And improve generated code for accessing package private methods from unresolved compiling class in the same package. Test: Additional test in 727-checker-unresolved-class Test: testrunner.py --host --optimizing --interpreter --jvm -t 727 Test: testrunner.py --host --optimizing Bug: 161898207 Change-Id: Ia34552d90620e8e0398099522a5a52b4a45df15d
Diffstat (limited to 'compiler/optimizing/instruction_builder.cc')
-rw-r--r--compiler/optimizing/instruction_builder.cc63
1 files changed, 61 insertions, 2 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 62932c989f..6839292397 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -42,6 +42,44 @@
namespace art {
+namespace {
+
+class SamePackageCompare {
+ public:
+ explicit SamePackageCompare(const DexCompilationUnit& dex_compilation_unit)
+ : dex_compilation_unit_(dex_compilation_unit) {}
+
+ bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (klass->GetClassLoader() != dex_compilation_unit_.GetClassLoader().Get()) {
+ return false;
+ }
+ if (referrers_descriptor_ == nullptr) {
+ const DexFile* dex_file = dex_compilation_unit_.GetDexFile();
+ uint32_t referrers_method_idx = dex_compilation_unit_.GetDexMethodIndex();
+ referrers_descriptor_ =
+ dex_file->StringByTypeIdx(dex_file->GetMethodId(referrers_method_idx).class_idx_);
+ referrers_package_length_ = PackageLength(referrers_descriptor_);
+ }
+ std::string temp;
+ const char* klass_descriptor = klass->GetDescriptor(&temp);
+ size_t klass_package_length = PackageLength(klass_descriptor);
+ return (referrers_package_length_ == klass_package_length) &&
+ memcmp(referrers_descriptor_, klass_descriptor, referrers_package_length_) == 0;
+ };
+
+ private:
+ static size_t PackageLength(const char* descriptor) {
+ const char* slash_pos = strrchr(descriptor, '/');
+ return (slash_pos != nullptr) ? static_cast<size_t>(slash_pos - descriptor) : 0u;
+ }
+
+ const DexCompilationUnit& dex_compilation_unit_;
+ const char* referrers_descriptor_ = nullptr;
+ size_t referrers_package_length_ = 0u;
+};
+
+} // anonymous namespace
+
HInstructionBuilder::HInstructionBuilder(HGraph* graph,
HBasicBlockBuilder* block_builder,
SsaBuilder* ssa_builder,
@@ -858,8 +896,29 @@ static ArtMethod* ResolveMethod(uint16_t method_idx,
// resolved because, for example, we don't find a superclass in the classpath.
if (referrer == nullptr) {
// The class linker cannot check access without a referrer, so we have to do it.
- // Fall back to HInvokeUnresolved if the method isn't public.
- if (!resolved_method->IsPublic()) {
+ // Check if the declaring class or referencing class is accessible.
+ SamePackageCompare same_package(dex_compilation_unit);
+ ObjPtr<mirror::Class> declaring_class = resolved_method->GetDeclaringClass();
+ bool declaring_class_accessible = declaring_class->IsPublic() || same_package(declaring_class);
+ if (!declaring_class_accessible) {
+ // It is possible to access members from an inaccessible superclass
+ // by referencing them through an accessible subclass.
+ ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
+ dex_compilation_unit.GetDexFile()->GetMethodId(method_idx).class_idx_,
+ dex_compilation_unit.GetDexCache().Get(),
+ class_loader.Get());
+ DCHECK(referenced_class != nullptr); // Must have been resolved when resolving the method.
+ if (!referenced_class->IsPublic() && !same_package(referenced_class)) {
+ return nullptr;
+ }
+ }
+ // Check whether the method itself is accessible.
+ // Since the referrer is unresolved but the method is resolved, it cannot be
+ // inside the same class, so a private method is known to be inaccessible.
+ // And without a resolved referrer, we cannot check for protected member access
+ // in superlass, so we handle only access to public member or within the package.
+ if (resolved_method->IsPrivate() ||
+ (!resolved_method->IsPublic() && !declaring_class_accessible)) {
return nullptr;
}
}