diff options
author | 2022-07-06 10:01:58 +0100 | |
---|---|---|
committer | 2022-07-07 16:58:21 +0000 | |
commit | d88c1499efe2f718f3cc1f45a3dc178471b22ce6 (patch) | |
tree | d28e20d9a4f87d2c1fc9a867b111cdc818ff250a /runtime/art_method.cc | |
parent | 4a21275dfb1bc58ede8141cbfd103ad46c3fcf2d (diff) |
Fix one edge case at method linking to throw at runtime.
If we could not find a public implementation for a public method, throw
an IllegalAccessError at runtime, when the method is actually called,
instead of when the class is being created.
Test: 840-resolution
Test: 182-method-linking
Change-Id: I741c7d0f6fc3b90a5d1614e1a9b76985a2eb32e2
Diffstat (limited to 'runtime/art_method.cc')
-rw-r--r-- | runtime/art_method.cc | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/runtime/art_method.cc b/runtime/art_method.cc index cef9d7b9bd..71f08e7b4d 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -150,10 +150,34 @@ uint16_t ArtMethod::FindObsoleteDexClassDefIndex() { return dex_file->GetIndexForClassDef(*class_def); } -void ArtMethod::ThrowInvocationTimeError() { +void ArtMethod::ThrowInvocationTimeError(ObjPtr<mirror::Object> receiver) { DCHECK(!IsInvokable()); if (IsDefaultConflicting()) { ThrowIncompatibleClassChangeErrorForMethodConflict(this); + } else if (GetDeclaringClass()->IsInterface() && receiver != nullptr) { + // If this was an interface call, check whether there is a method in the + // superclass chain that isn't public. In this situation, we should throw an + // IllegalAccessError. + DCHECK(IsAbstract()); + ObjPtr<mirror::Class> current = receiver->GetClass(); + while (current != nullptr) { + for (ArtMethod& method : current->GetDeclaredMethodsSlice(kRuntimePointerSize)) { + ArtMethod* np_method = method.GetInterfaceMethodIfProxy(kRuntimePointerSize); + if (!np_method->IsStatic() && + np_method->GetNameView() == GetNameView() && + np_method->GetSignature() == GetSignature()) { + if (!np_method->IsPublic()) { + ThrowIllegalAccessErrorForImplementingMethod(receiver->GetClass(), np_method, this); + return; + } else if (np_method->IsAbstract()) { + ThrowAbstractMethodError(this); + return; + } + } + } + current = current->GetSuperClass(); + } + ThrowAbstractMethodError(this); } else { DCHECK(IsAbstract()); ThrowAbstractMethodError(this); |