diff options
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 1 | ||||
-rw-r--r-- | runtime/class_linker-inl.h | 6 | ||||
-rw-r--r-- | runtime/class_linker.cc | 13 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 2 | ||||
-rw-r--r-- | runtime/mirror/dex_cache.cc | 4 | ||||
-rw-r--r-- | runtime/mirror/dex_cache.h | 1 | ||||
-rw-r--r-- | test/827-resolve-method/expected-stderr.txt | 0 | ||||
-rw-r--r-- | test/827-resolve-method/expected-stdout.txt | 1 | ||||
-rw-r--r-- | test/827-resolve-method/info.txt | 1 | ||||
-rw-r--r-- | test/827-resolve-method/src-ex/Caller.java | 26 | ||||
-rw-r--r-- | test/827-resolve-method/src/Main.java | 56 | ||||
-rw-r--r-- | test/827-resolve-method/src/pkg1/SubClass.java | 27 | ||||
-rw-r--r-- | test/knownfailures.json | 1 |
13 files changed, 138 insertions, 1 deletions
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index b48debcb04..c2fbadf016 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -759,6 +759,7 @@ art::mirror::DexCache* Redefiner::ClassRedefinition::CreateNewDexCache( } art::WriterMutexLock mu(driver_->self_, *art::Locks::dex_lock_); cache->SetLocation(location.Get()); + cache->SetClassLoader(loader.Get()); cache->InitializeNativeFields(dex_file_.get(), loader.IsNull() ? driver_->runtime_->GetLinearAlloc() : loader->GetAllocator()); diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index c45f001aa3..13191016b2 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -164,6 +164,7 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(dex_cache != nullptr); + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); Thread::PoisonObjectPointersIfDebug(); ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx); if (resolved == nullptr) { @@ -212,6 +213,7 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType( dex::TypeIndex type_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, dex_cache, class_loader); @@ -273,6 +275,7 @@ inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_c InvokeType type, uint32_t method_idx, ObjPtr<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); return CheckInvokeClassMismatch<kThrow>( dex_cache, type, @@ -288,6 +291,7 @@ inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_c inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); if (resolved == nullptr) { const DexFile& dex_file = *dex_cache->GetDexFile(); @@ -433,6 +437,7 @@ inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField( field_idx); if (field == nullptr) { + referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader(); field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static); } @@ -449,6 +454,7 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, field_idx); if (UNLIKELY(resolved_field == nullptr)) { StackHandleScope<2> hs(Thread::Current()); + referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader())); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 314aa29ce6..f94bffd58e 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -8867,6 +8867,7 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); const DexFile& dex_file = *dex_cache->GetDexFile(); const char* descriptor = dex_file.StringByTypeIdx(type_idx); ObjPtr<mirror::Class> type = LookupResolvedType(descriptor, class_loader); @@ -8914,6 +8915,7 @@ template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_id ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); Thread* self = Thread::Current(); const char* descriptor = dex_cache->GetDexFile()->StringByTypeIdx(type_idx); ObjPtr<mirror::Class> resolved = FindClass(self, descriptor, class_loader); @@ -8944,6 +8946,7 @@ ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader, uint32_t method_idx) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); // Search for the method using dex_cache and method_idx. The Class::Find*Method() // functions can optimize the search if the dex_cache is the same as the DexCache // of the class, with fall-back to name and signature search otherwise. @@ -9004,6 +9007,7 @@ static bool CheckNoSuchMethod(ArtMethod* method, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); return method == nullptr || hiddenapi::ShouldDenyAccessToMember(method, hiddenapi::AccessContext(class_loader, dex_cache), @@ -9014,6 +9018,7 @@ ArtMethod* ClassLinker::FindIncompatibleMethod(ObjPtr<mirror::Class> klass, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader, uint32_t method_idx) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); if (klass->IsInterface()) { ArtMethod* method = klass->FindClassMethod(dex_cache, method_idx, image_pointer_size_); return CheckNoSuchMethod(method, dex_cache, class_loader) ? nullptr : method; @@ -9036,6 +9041,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer, InvokeType type) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump(); DCHECK(dex_cache != nullptr); DCHECK(referrer == nullptr || !referrer->IsProxyMethod()); @@ -9130,6 +9136,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); Thread::PoisonObjectPointersIfDebug(); if (resolved != nullptr) { @@ -9163,6 +9170,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader, bool is_static) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); const DexFile& dex_file = *dex_cache->GetDexFile(); const dex::FieldId& field_id = dex_file.GetFieldId(field_idx); ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(field_id.class_idx_); @@ -9183,6 +9191,7 @@ ArtField* ClassLinker::ResolveField(uint32_t field_idx, Handle<mirror::ClassLoader> class_loader, bool is_static) { DCHECK(dex_cache != nullptr); + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump(); ArtField* resolved = dex_cache->GetResolvedField(field_idx); Thread::PoisonObjectPointersIfDebug(); @@ -9210,6 +9219,7 @@ ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(dex_cache != nullptr); + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); ArtField* resolved = dex_cache->GetResolvedField(field_idx); Thread::PoisonObjectPointersIfDebug(); if (resolved != nullptr) { @@ -9237,6 +9247,7 @@ ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass, ObjPtr<mirror::ClassLoader> class_loader, uint32_t field_idx, bool is_static) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); ArtField* resolved = is_static ? klass->FindStaticField(dex_cache, field_idx) : klass->FindInstanceField(dex_cache, field_idx); if (resolved != nullptr && @@ -9257,6 +9268,7 @@ ArtField* ClassLinker::FindResolvedFieldJLS(ObjPtr<mirror::Class> klass, ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader, uint32_t field_idx) { + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr()); ArtField* resolved = klass->FindField(dex_cache, field_idx); if (resolved != nullptr && @@ -9280,6 +9292,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType( Handle<mirror::ClassLoader> class_loader) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); DCHECK(dex_cache != nullptr); + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); ObjPtr<mirror::MethodType> resolved = dex_cache->GetResolvedMethodType(proto_idx); if (resolved != nullptr) { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 3295364c03..b59dc18964 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -468,7 +468,7 @@ inline bool Class::ResolvedFieldAccessTest(ObjPtr<Class> access_to, ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType( class_idx, dex_cache, - access_to->GetClassLoader()); + GetClassLoader()); DCHECK(dex_access_to != nullptr); if (UNLIKELY(!this->CanAccess(dex_access_to))) { if (throw_on_failure) { diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index 1b9558e6df..d100f32340 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -247,6 +247,10 @@ void DexCache::SetClassLoader(ObjPtr<ClassLoader> class_loader) { SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_), class_loader); } +ObjPtr<ClassLoader> DexCache::GetClassLoader() { + return GetFieldObject<mirror::ClassLoader>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_)); +} + #if !defined(__aarch64__) && !defined(__x86_64__) static pthread_mutex_t dex_cache_slow_atomic_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 03ff2218de..f02ddc6bfb 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -476,6 +476,7 @@ class MANAGED DexCache final : public Object { void VisitReflectiveTargets(ReflectiveValueVisitor* visitor) REQUIRES(Locks::mutator_lock_); void SetClassLoader(ObjPtr<ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<ClassLoader> GetClassLoader() REQUIRES_SHARED(Locks::mutator_lock_); private: void SetNativeArrays(StringDexCacheType* strings, diff --git a/test/827-resolve-method/expected-stderr.txt b/test/827-resolve-method/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/827-resolve-method/expected-stderr.txt diff --git a/test/827-resolve-method/expected-stdout.txt b/test/827-resolve-method/expected-stdout.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/827-resolve-method/expected-stdout.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/827-resolve-method/info.txt b/test/827-resolve-method/info.txt new file mode 100644 index 0000000000..8b7f1732f6 --- /dev/null +++ b/test/827-resolve-method/info.txt @@ -0,0 +1 @@ +Regression test for method resolution. diff --git a/test/827-resolve-method/src-ex/Caller.java b/test/827-resolve-method/src-ex/Caller.java new file mode 100644 index 0000000000..fc1890ec26 --- /dev/null +++ b/test/827-resolve-method/src-ex/Caller.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Caller { + public static void doCall() { + // `callMethod` is declared in a class that isn't visible to `Caller`, however, we are + // accessing it through `LocalCall` and that makes it accessible. + LocalClass.callMethod(); + } +} + +class LocalClass extends pkg1.SubClass { +} diff --git a/test/827-resolve-method/src/Main.java b/test/827-resolve-method/src/Main.java new file mode 100644 index 0000000000..c1c94dae03 --- /dev/null +++ b/test/827-resolve-method/src/Main.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +final class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + MyLocalClass.callMethod(); + loadClass(); + } + + public static void loadClass() throws Exception { + Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); + if (pathClassLoader == null) { + throw new AssertionError("Couldn't find path class loader class"); + } + Constructor<?> constructor = + pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class); + ClassLoader loader = (ClassLoader) constructor.newInstance( + DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader()); + Class<?> otherClass = loader.loadClass("Caller"); + + // Run the method in interpreter / AOT mode. + otherClass.getMethod("doCall").invoke(null); + + // Run the method in JIT mode. + ensureJitCompiled(otherClass, "doCall"); + otherClass.getMethod("doCall").invoke(null); + } + + private static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path"); + private static final String DEX_LOCATION = System.getenv("DEX_LOCATION"); + private static final String DEX_FILE = + new File(DEX_LOCATION, "827-resolve-method-ex.jar").getAbsolutePath(); + + private static native void ensureJitCompiled(Class<?> cls, String methodName); +} + +class MyLocalClass extends pkg1.SubClass { +} diff --git a/test/827-resolve-method/src/pkg1/SubClass.java b/test/827-resolve-method/src/pkg1/SubClass.java new file mode 100644 index 0000000000..78e9346a14 --- /dev/null +++ b/test/827-resolve-method/src/pkg1/SubClass.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pkg1; + +// `SuperClass` is only visible to classes in packge `pkg1`. +class SuperClass { + public static void callMethod() { + } +} + +// Any class that extends `SubClass` will be able to access `SuperClass.callMethod`. +public class SubClass extends SuperClass { +} diff --git a/test/knownfailures.json b/test/knownfailures.json index 367cfdc604..01a7f3b2c4 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -1154,6 +1154,7 @@ "820-vdex-multidex", "821-many-args", "822-hiddenapi-future", + "827-resolve-method", "999-redefine-hiddenapi", "1000-non-moving-space-stress", "1001-app-image-regions", |