diff options
author | 2016-01-29 12:24:48 -0800 | |
---|---|---|
committer | 2016-01-29 12:26:14 -0800 | |
commit | 5a5598609f4f65f446e46327e7b6789c41c92bde (patch) | |
tree | 5556534d92e80d0bf141575564f4d8158e73bdef | |
parent | 2624ffcdbafd0d89cb92f688d4c264bb08a2522c (diff) |
Fix issue with exception type resolution during linking.
When using default methods that cross dex-files we would sometimes
attempt to lookup method information using the wrong dex file. This
fixes this issue.
Bug: 26872564
Change-Id: I3c4b64ef970017356962060f3bd3781b4629a3c8
-rw-r--r-- | runtime/class_linker.cc | 13 | ||||
-rw-r--r-- | runtime/class_linker.h | 5 | ||||
-rw-r--r-- | test/973-default-multidex/expected.txt | 1 | ||||
-rw-r--r-- | test/973-default-multidex/info.txt | 5 | ||||
-rw-r--r-- | test/973-default-multidex/smali-multidex/iface.smali | 40 | ||||
-rw-r--r-- | test/973-default-multidex/smali/concreteclass.smali | 47 | ||||
-rw-r--r-- | test/973-default-multidex/src/Main.java | 31 |
7 files changed, 132 insertions, 10 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index e98baba5ab..5ef199cb60 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3666,7 +3666,7 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { } self->AssertNoPendingException(); // Make sure all classes referenced by catch blocks are resolved. - ResolveClassExceptionHandlerTypes(dex_file, klass); + ResolveClassExceptionHandlerTypes(klass); if (verifier_failure == verifier::MethodVerifier::kNoFailure) { // Even though there were no verifier failures we need to respect whether the super-class and // super-default-interfaces were verified or requiring runtime reverification. @@ -3802,17 +3802,16 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, UNREACHABLE(); } -void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, - Handle<mirror::Class> klass) { +void ClassLinker::ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) { for (ArtMethod& method : klass->GetMethods(image_pointer_size_)) { - ResolveMethodExceptionHandlerTypes(dex_file, &method); + ResolveMethodExceptionHandlerTypes(&method); } } -void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, - ArtMethod* method) { +void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) { // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod. - const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset()); + const DexFile::CodeItem* code_item = + method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset()); if (code_item == nullptr) { return; // native or abstract method } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 99dd073d56..5176cbd3ea 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -441,11 +441,10 @@ class ClassLinker { mirror::Class::Status& oat_file_class_status) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, - Handle<mirror::Class> klass) + void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, ArtMethod* klass) + void ResolveMethodExceptionHandlerTypes(ArtMethod* klass) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); diff --git a/test/973-default-multidex/expected.txt b/test/973-default-multidex/expected.txt new file mode 100644 index 0000000000..b376e81554 --- /dev/null +++ b/test/973-default-multidex/expected.txt @@ -0,0 +1 @@ +STRING!!!STRING!!! diff --git a/test/973-default-multidex/info.txt b/test/973-default-multidex/info.txt new file mode 100644 index 0000000000..17c0b7d279 --- /dev/null +++ b/test/973-default-multidex/info.txt @@ -0,0 +1,5 @@ +Smali-based tests for interface default methods. + +Obviously needs to run under ART or a Java 8 Language runtime and compiler. + +Tests that we handle referenced throws across dex files. diff --git a/test/973-default-multidex/smali-multidex/iface.smali b/test/973-default-multidex/smali-multidex/iface.smali new file mode 100644 index 0000000000..fa6d27f527 --- /dev/null +++ b/test/973-default-multidex/smali-multidex/iface.smali @@ -0,0 +1,40 @@ +# +# Copyright (C) 2016 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. + + +.class public abstract interface LIface; +.super Ljava/lang/Object; + +# public interface Iface { +# public default String getTwice() { +# return getString() + getString(); +# } +# public String getString(); +# } + +.method public getTwice()Ljava/lang/String; +.locals 2 + invoke-static {p0}, Ljava/util/Objects;->requireNonNull(Ljava/lang/Object;)Ljava/lang/Object; + invoke-interface {p0}, LIface;->getString()Ljava/lang/String; + move-result-object v0 + invoke-interface {p0}, LIface;->getString()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method + +.method public abstract getString()Ljava/lang/String; +.end method diff --git a/test/973-default-multidex/smali/concreteclass.smali b/test/973-default-multidex/smali/concreteclass.smali new file mode 100644 index 0000000000..e177f2698a --- /dev/null +++ b/test/973-default-multidex/smali/concreteclass.smali @@ -0,0 +1,47 @@ +# +# Copyright (C) 2016 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. + + +.class public LConcreteClass; +.super Ljava/lang/Object; +.implements LIface; + +# public class ConcreteClass implements Iface { +# public String getString() { +# return "STRING!!!"; +# } +# public String callMethod() { +# return this.getTwice(); +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public getString()Ljava/lang/String; +.registers 2 + const-string v0, "STRING!!!" + return-object v0 +.end method + +.method public callMethod()Ljava/lang/String; +.registers 2 + invoke-virtual {p0}, LConcreteClass;->getTwice()Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method diff --git a/test/973-default-multidex/src/Main.java b/test/973-default-multidex/src/Main.java new file mode 100644 index 0000000000..b93265a5b8 --- /dev/null +++ b/test/973-default-multidex/src/Main.java @@ -0,0 +1,31 @@ +/* + * Copyright 2016 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.lang.reflect.*; +public class Main { + public static void main(String[] args) { + Class<?> c = null; + try { + c = Class.forName("ConcreteClass"); + Method m = c.getMethod("callMethod"); + System.out.println(m.invoke(c.newInstance(), new Object[0])); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("FAILED: Could not call method"); + return; + } + } +} |