Make array class with erroneous component also erroneous under AOT.
We cannot encode such array classes in an image, so just prevent
creating them.
Test: test.py
Test: image_test
Bug: 240582357
Change-Id: I2efdf3cc7bc72169713eb9b849824d71145764ac
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 1813913..3ec163cb 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -706,6 +706,7 @@
# Check ART jar files which are needed for gtests.
self._checker.check_art_test_data('art-gtest-jars-AbstractMethod.jar')
+ self._checker.check_art_test_data('art-gtest-jars-ArrayClassWithUnresolvedComponent.dex')
self._checker.check_art_test_data('art-gtest-jars-MyClassNatives.jar')
self._checker.check_art_test_data('art-gtest-jars-Main.jar')
self._checker.check_art_test_data('art-gtest-jars-ProtoCompare.jar')
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index e6116e9..b111e63 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -459,6 +459,7 @@
name: "art_dex2oat_tests_defaults",
data: [
":art-gtest-jars-AbstractMethod",
+ ":art-gtest-jars-ArrayClassWithUnresolvedComponent",
":art-gtest-jars-DefaultMethods",
":art-gtest-jars-Dex2oatVdexPublicSdkDex",
":art-gtest-jars-Dex2oatVdexTestDex",
diff --git a/dex2oat/art_standalone_dex2oat_tests.xml b/dex2oat/art_standalone_dex2oat_tests.xml
index 1707887..1b6ced8 100644
--- a/dex2oat/art_standalone_dex2oat_tests.xml
+++ b/dex2oat/art_standalone_dex2oat_tests.xml
@@ -23,6 +23,7 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="art-gtest-jars-AbstractMethod.jar->/data/local/tmp/art_standalone_dex2oat_tests/art-gtest-jars-AbstractMethod.jar" />
+ <option name="push" value="art-gtest-jars-ArrayClassWithUnresolvedComponent.dex->/data/local/tmp/art_standalone_dex2oat_tests/art-gtest-jars-ArrayClassWithUnresolvedComponent.dex" />
<option name="push" value="art-gtest-jars-DefaultMethods.jar->/data/local/tmp/art_standalone_dex2oat_tests/art-gtest-jars-DefaultMethods.jar" />
<option name="push" value="art-gtest-jars-Dex2oatVdexPublicSdkDex.dex->/data/local/tmp/art_standalone_dex2oat_tests/art-gtest-jars-Dex2oatVdexPublicSdkDex.dex" />
<option name="push" value="art-gtest-jars-Dex2oatVdexTestDex.jar->/data/local/tmp/art_standalone_dex2oat_tests/art-gtest-jars-Dex2oatVdexTestDex.jar" />
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index d9509b0..5a72178 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -1109,6 +1109,7 @@
HashSet<std::string>* image_classes)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(self, Thread::Current());
+ DCHECK(klass->IsResolved());
Runtime* runtime = Runtime::Current();
gc::Heap* heap = runtime->GetHeap();
if (heap->ObjectIsInBootImageSpace(klass)) {
diff --git a/dex2oat/linker/image_test.cc b/dex2oat/linker/image_test.cc
index 33d122b..357d9c7 100644
--- a/dex2oat/linker/image_test.cc
+++ b/dex2oat/linker/image_test.cc
@@ -176,5 +176,27 @@
/*image_classes_failing_aot_clinit=*/ {"LClassToInitialize;"});
}
+TEST_F(ImageTest, TestImageClassWithArrayClassWithUnresolvedComponent) {
+ CompilationHelper helper;
+ Compile(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
+ helper,
+ "ArrayClassWithUnresolvedComponent",
+ /*image_classes=*/ {"LClassWithStatic;",
+ "LClassWithStaticConst;",
+ "[LClassWithMissingInterface;",
+ "[[LClassWithMissingInterface;",
+ "[LClassWithMissingSuper",
+ "[[LClassWithMissingSuper"},
+ /*image_classes_failing_aot_clinit=*/ {
+ "LClassWithStatic;",
+ "LClassWithStaticConst;"},
+ /*image_classes_failing_resolution=*/ {
+ "[LClassWithMissingInterface;",
+ "[[LClassWithMissingInterface;",
+ "[LClassWithMissingSuper",
+ "[[LClassWithMissingSuper"});
+}
+
} // namespace linker
} // namespace art
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 5c2d84c..b570d99 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -86,7 +86,8 @@
/*out*/ CompilationHelper& out_helper,
const std::string& extra_dex = "",
const std::initializer_list<std::string>& image_classes = {},
- const std::initializer_list<std::string>& image_classes_failing_aot_clinit = {});
+ const std::initializer_list<std::string>& image_classes_failing_aot_clinit = {},
+ const std::initializer_list<std::string>& image_classes_failing_resolution = {});
void SetUpRuntimeOptions(RuntimeOptions* options) override {
CommonCompilerTest::SetUpRuntimeOptions(options);
@@ -352,7 +353,8 @@
CompilationHelper& helper,
const std::string& extra_dex,
const std::initializer_list<std::string>& image_classes,
- const std::initializer_list<std::string>& image_classes_failing_aot_clinit) {
+ const std::initializer_list<std::string>& image_classes_failing_aot_clinit,
+ const std::initializer_list<std::string>& image_classes_failing_resolution) {
for (const std::string& image_class : image_classes_failing_aot_clinit) {
ASSERT_TRUE(ContainsElement(image_classes, image_class));
}
@@ -375,12 +377,14 @@
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
for (const std::string& image_class : image_classes) {
ObjPtr<mirror::Class> klass =
- class_linker->FindSystemClass(Thread::Current(), image_class.c_str());
- EXPECT_TRUE(klass != nullptr);
- EXPECT_TRUE(klass->IsResolved());
- if (ContainsElement(image_classes_failing_aot_clinit, image_class)) {
+ class_linker->LookupClass(Thread::Current(), image_class.c_str(), nullptr);
+ if (ContainsElement(image_classes_failing_resolution, image_class)) {
+ EXPECT_TRUE(klass == nullptr || klass->IsErroneousUnresolved());
+ } else if (ContainsElement(image_classes_failing_aot_clinit, image_class)) {
+ ASSERT_TRUE(klass != nullptr) << image_class;
EXPECT_FALSE(klass->IsInitialized());
} else {
+ ASSERT_TRUE(klass != nullptr) << image_class;
EXPECT_TRUE(klass->IsInitialized());
}
}
diff --git a/dex2oat/verifier_deps_test.cc b/dex2oat/verifier_deps_test.cc
index 708af04..27eadec 100644
--- a/dex2oat/verifier_deps_test.cc
+++ b/dex2oat/verifier_deps_test.cc
@@ -630,12 +630,5 @@
ASSERT_FALSE(buffer.empty());
}
-TEST_F(VerifierDepsTest, Assignable_Arrays) {
- ASSERT_TRUE(TestAssignabilityRecording(/* dst= */ "[LIface;",
- /* src= */ "[LMyClassExtendingInterface;"));
- ASSERT_FALSE(HasAssignable(
- "LIface;", "LMyClassExtendingInterface;"));
-}
-
} // namespace verifier
} // namespace art
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 78aac8b..51870a7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4143,10 +4143,11 @@
class_loader)));
if (component_type == nullptr) {
DCHECK(self->IsExceptionPending());
- // We need to accept erroneous classes as component types.
+ // We need to accept erroneous classes as component types. Under AOT, we
+ // don't accept them as we cannot encode the erroneous class in an image.
const size_t component_hash = ComputeModifiedUtf8Hash(descriptor + 1);
component_type.Assign(LookupClass(self, descriptor + 1, component_hash, class_loader.Get()));
- if (component_type == nullptr) {
+ if (component_type == nullptr || Runtime::Current()->IsAotCompiler()) {
DCHECK(self->IsExceptionPending());
return nullptr;
} else {
diff --git a/test/Android.bp b/test/Android.bp
index 1e28ac0..715aefd 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -1396,6 +1396,7 @@
srcs: [
":art-gtest-jars-AbstractMethod",
":art-gtest-jars-AllFields",
+ ":art-gtest-jars-ArrayClassWithUnresolvedComponent",
":art-gtest-jars-DefaultMethods",
":art-gtest-jars-ErroneousA",
":art-gtest-jars-ErroneousB",
@@ -1847,6 +1848,13 @@
}
genrule {
+ name: "art-gtest-jars-ArrayClassWithUnresolvedComponent",
+ defaults: ["art-gtest-jars-smali-defaults"],
+ srcs: ["ArrayClassWithUnresolvedComponent/*.smali"],
+ out: ["art-gtest-jars-ArrayClassWithUnresolvedComponent.dex"],
+}
+
+genrule {
name: "art-gtest-jars-LinkageTest",
defaults: ["art-gtest-jars-smali-defaults"],
srcs: ["LinkageTest/*.smali"],
diff --git a/test/ArrayClassWithUnresolvedComponent/ClassWithMissingInterface.smali b/test/ArrayClassWithUnresolvedComponent/ClassWithMissingInterface.smali
new file mode 100644
index 0000000..f68d70c
--- /dev/null
+++ b/test/ArrayClassWithUnresolvedComponent/ClassWithMissingInterface.smali
@@ -0,0 +1,18 @@
+# Copyright (C) 2022 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 LClassWithMissingInterface;
+
+.super Ljava/lang/Object;
+.implements LMissingInterface;
diff --git a/test/ArrayClassWithUnresolvedComponent/ClassWithMissingSuper.smali b/test/ArrayClassWithUnresolvedComponent/ClassWithMissingSuper.smali
new file mode 100644
index 0000000..134302c
--- /dev/null
+++ b/test/ArrayClassWithUnresolvedComponent/ClassWithMissingSuper.smali
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 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 LClassWithMissingSuper;
+
+.super LMissingClass;
diff --git a/test/ArrayClassWithUnresolvedComponent/ClassWithStatic.smali b/test/ArrayClassWithUnresolvedComponent/ClassWithStatic.smali
new file mode 100644
index 0000000..f35e5f0
--- /dev/null
+++ b/test/ArrayClassWithUnresolvedComponent/ClassWithStatic.smali
@@ -0,0 +1,28 @@
+# Copyright (C) 2022 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 LClassWithStatic;
+
+.super Ljava/lang/Object;
+
+.method static constructor <clinit>()V
+ .registers 1
+ const-string v0, "[LClassWithMissingInterface;"
+ invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+ move-result-object v0
+ sput-object v0, LClassWithStatic;->field:Ljava/lang/Class;
+ return-void
+.end method
+
+.field public static field:Ljava/lang/Class;
diff --git a/test/ArrayClassWithUnresolvedComponent/ClassWithStaticConst.smali b/test/ArrayClassWithUnresolvedComponent/ClassWithStaticConst.smali
new file mode 100644
index 0000000..68aecfb
--- /dev/null
+++ b/test/ArrayClassWithUnresolvedComponent/ClassWithStaticConst.smali
@@ -0,0 +1,26 @@
+# Copyright (C) 2022 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 LClassWithStaticConst;
+
+.super Ljava/lang/Object;
+
+.method static constructor <clinit>()V
+ .registers 1
+ const-class v0, [LClassWithMissingInterface;
+ sput-object v0, LClassWithStaticConst;->field:Ljava/lang/Class;
+ return-void
+.end method
+
+.field public static field:Ljava/lang/Class;