summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Roland Levillain <rpl@google.com> 2016-05-18 15:52:54 +0100
committer Roland Levillain <rpl@google.com> 2016-05-18 15:52:54 +0100
commit989ab3b3034d16a57f5a893d73ed804169d8eced (patch)
treebda9791bb3b9917a34bb0f6d6de560ab967ffea4
parenta741785dddab1f4b79253514287860d11c5800c6 (diff)
Catch classes inheriting from themselves in the class linker.
(cherry picked from commit 90328ac545f65759a8e4fb217a75332906795518) Bug: 28685551 Bug: 27682580 Bug: 28830038 Change-Id: If568013bf3c82c1df9b282522712d9af5ca5945d
-rw-r--r--runtime/class_linker.cc13
-rw-r--r--runtime/common_throws.cc7
-rw-r--r--runtime/common_throws.h3
-rw-r--r--test/804-class-extends-itself/expected.txt2
-rw-r--r--test/804-class-extends-itself/info.txt1
-rw-r--r--test/804-class-extends-itself/smali/Main.smali57
-rw-r--r--test/804-class-extends-itself/smali/b_28685551.smali18
7 files changed, 101 insertions, 0 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1835c728b3..8fcb6b25fa 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5316,6 +5316,19 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
uint16_t super_class_idx = class_def.superclass_idx_;
if (super_class_idx != DexFile::kDexNoIndex16) {
+ // Check that a class does not inherit from itself directly.
+ //
+ // TODO: This is a cheap check to detect the straightforward case
+ // of a class extending itself (b/28685551), but we should do a
+ // proper cycle detection on loaded classes, to detect all cases
+ // of class circularity errors (b/28830038).
+ if (super_class_idx == class_def.class_idx_) {
+ ThrowClassCircularityError(klass.Get(),
+ "Class %s extends itself",
+ PrettyDescriptor(klass.Get()).c_str());
+ return false;
+ }
+
mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.Get());
if (super_class == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index f8e32c41bf..75cce424e9 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -137,6 +137,13 @@ void ThrowClassCircularityError(mirror::Class* c) {
ThrowException("Ljava/lang/ClassCircularityError;", c, msg.str().c_str());
}
+void ThrowClassCircularityError(mirror::Class* c, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException("Ljava/lang/ClassCircularityError;", c, fmt, &args);
+ va_end(args);
+}
+
// ClassFormatError
void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 39c4e52b15..c3a1f09db3 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -58,6 +58,9 @@ void ThrowArrayStoreException(mirror::Class* element_class, mirror::Class* array
void ThrowClassCircularityError(mirror::Class* c)
SHARED_REQUIRES(Locks::mutator_lock_) COLD_ATTR;
+void ThrowClassCircularityError(mirror::Class* c, const char* fmt, ...)
+ SHARED_REQUIRES(Locks::mutator_lock_) COLD_ATTR;
+
// ClassCastException
void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type)
diff --git a/test/804-class-extends-itself/expected.txt b/test/804-class-extends-itself/expected.txt
new file mode 100644
index 0000000000..b98f963ce7
--- /dev/null
+++ b/test/804-class-extends-itself/expected.txt
@@ -0,0 +1,2 @@
+Caught ClassCircularityError
+Done!
diff --git a/test/804-class-extends-itself/info.txt b/test/804-class-extends-itself/info.txt
new file mode 100644
index 0000000000..c48934c21b
--- /dev/null
+++ b/test/804-class-extends-itself/info.txt
@@ -0,0 +1 @@
+Exercise class linker check for classes extending themselves (b/28685551).
diff --git a/test/804-class-extends-itself/smali/Main.smali b/test/804-class-extends-itself/smali/Main.smali
new file mode 100644
index 0000000000..5c349edcc9
--- /dev/null
+++ b/test/804-class-extends-itself/smali/Main.smali
@@ -0,0 +1,57 @@
+# 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.
+
+# We cannot implement Main in Java, as this would require to run
+# dexmerger (to merge the Dex file produced from Smali code and the
+# Dex file produced from Java code), which loops indefinitely when
+# processing class B28685551, as this class inherits from itself. As
+# a workaround, implement Main using Smali (we could also have used
+# multidex, but this requires a custom build script).
+
+.class public LMain;
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+ .registers 3
+ .param p0, "args"
+
+ invoke-static {}, LMain;->test()V
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ const-string v1, "Done!"
+ invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+.end method
+
+.method static test()V
+ .registers 4
+
+ :try_start
+ const-string v2, "B28685551"
+ invoke-static {v2}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+ :try_end
+ .catch Ljava/lang/ClassCircularityError; {:try_start .. :try_end} :catch
+
+ move-result-object v0
+
+ :goto_7
+ return-void
+
+ :catch
+ move-exception v1
+ .local v1, "e":Ljava/lang/ClassCircularityError;
+ sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ const-string v3, "Caught ClassCircularityError"
+ invoke-virtual {v2, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ goto :goto_7
+.end method
diff --git a/test/804-class-extends-itself/smali/b_28685551.smali b/test/804-class-extends-itself/smali/b_28685551.smali
new file mode 100644
index 0000000000..d98c6e3b32
--- /dev/null
+++ b/test/804-class-extends-itself/smali/b_28685551.smali
@@ -0,0 +1,18 @@
+# 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.
+
+# Regression test for a class inheriting from itself.
+
+.class public LB28685551;
+.super LB28685551;