summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc55
1 files changed, 53 insertions, 2 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 879544f42f..0a37f26135 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6160,6 +6160,7 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
return resolved;
}
+template <ClassLinker::ResolveMode kResolveMode>
ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
@@ -6171,6 +6172,12 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
+ if (kResolveMode == ClassLinker::kForceICCECheck) {
+ if (resolved->CheckIncompatibleClassChange(type)) {
+ ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
+ return nullptr;
+ }
+ }
return resolved;
}
// Fail, get the declaring class.
@@ -6189,8 +6196,36 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
break;
case kInterface:
- resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());
+ // We have to check whether the method id really belongs to an interface (dex static bytecode
+ // constraint A15). Otherwise you must not invoke-interface on it.
+ //
+ // This is not symmetric to A12-A14 (direct, static, virtual), as using FindInterfaceMethod
+ // assumes that the given type is an interface, and will check the interface table if the
+ // method isn't declared in the class. So it may find an interface method (usually by name
+ // in the handling below, but we do the constraint check early). In that case,
+ // CheckIncompatibleClassChange will succeed (as it is called on an interface method)
+ // unexpectedly.
+ // Example:
+ // interface I {
+ // foo()
+ // }
+ // class A implements I {
+ // ...
+ // }
+ // class B extends A {
+ // ...
+ // }
+ // invoke-interface B.foo
+ // -> FindInterfaceMethod finds I.foo (interface method), not A.foo (miranda method)
+ if (UNLIKELY(!klass->IsInterface())) {
+ ThrowIncompatibleClassChangeError(klass,
+ "Found class %s, but interface was expected",
+ PrettyDescriptor(klass).c_str());
+ return nullptr;
+ } else {
+ resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);
+ DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());
+ }
break;
case kSuper: // Fall-through.
case kVirtual:
@@ -6792,4 +6827,20 @@ void ClassLinker::CleanupClassLoaders() {
}
}
+// Instantiate ResolveMethod.
+template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kForceICCECheck>(
+ const DexFile& dex_file,
+ uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ ArtMethod* referrer,
+ InvokeType type);
+template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kNoICCECheckForCache>(
+ const DexFile& dex_file,
+ uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ ArtMethod* referrer,
+ InvokeType type);
+
} // namespace art