diff options
author | 2015-12-08 22:33:23 +0000 | |
---|---|---|
committer | 2015-12-08 22:33:23 +0000 | |
commit | eb5ddd7b02ce2d25d4f28f85a13aac628526e1c1 (patch) | |
tree | 8f655b382e73222e70e30daaeedc3999014aa7ae /runtime/class_linker.cc | |
parent | 2433d4e17c3006b8262a0d9421e201fc84777208 (diff) | |
parent | dae24142127c64551142a50423085aabdb0a6060 (diff) |
Merge "ART: Check invoke-interface earlier in verifier"
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 55 |
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 |