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;