xref: /aosp_15_r20/art/dex2oat/linker/image_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <string.h>
18 #include <vector>
19 
20 #include "image_test.h"
21 
22 #include "base/pointer_size.h"
23 #include "oat/image.h"
24 #include "scoped_thread_state_change-inl.h"
25 #include "thread.h"
26 
27 namespace art {
28 namespace linker {
29 
TEST_F(ImageTest,TestImageLayout)30 TEST_F(ImageTest, TestImageLayout) {
31   std::vector<size_t> image_sizes;
32   std::vector<size_t> image_sizes_extra;
33   // Compile multi-image with ImageLayoutA being the last image.
34   {
35     CompilationHelper helper;
36     Compile(ImageHeader::kStorageModeUncompressed,
37             /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
38             helper,
39             "ImageLayoutA",
40             {"LMyClass;"});
41     image_sizes = helper.GetImageObjectSectionSizes();
42   }
43   TearDown();
44   runtime_.reset();
45   SetUp();
46   // Compile multi-image with ImageLayoutB being the last image.
47   {
48     CompilationHelper helper;
49     Compile(ImageHeader::kStorageModeUncompressed,
50             /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
51             helper,
52             "ImageLayoutB",
53             {"LMyClass;"});
54     image_sizes_extra = helper.GetImageObjectSectionSizes();
55   }
56   // Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the
57   // first two images.
58   ASSERT_EQ(image_sizes.size(), image_sizes.size());
59   // Sizes of the object sections should be the same for all but the last image.
60   for (size_t i = 0; i < image_sizes.size() - 1; ++i) {
61     EXPECT_EQ(image_sizes[i], image_sizes_extra[i]);
62   }
63   // Last image should be larger since it has a hash map and a string.
64   EXPECT_LT(image_sizes.back(), image_sizes_extra.back());
65 }
66 
TEST_F(ImageTest,ImageHeaderIsValid)67 TEST_F(ImageTest, ImageHeaderIsValid) {
68   uint32_t image_begin = ART_BASE_ADDRESS;
69   uint32_t image_size_ = kElfSegmentAlignment;
70   uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB);
71   uint32_t oat_checksum = 0;
72   uint32_t oat_file_begin = ART_BASE_ADDRESS + (kElfSegmentAlignment);
73   uint32_t oat_data_begin = ART_BASE_ADDRESS + (2 * kElfSegmentAlignment);
74   uint32_t oat_data_end = ART_BASE_ADDRESS + (2 * kElfSegmentAlignment + 1 * KB);
75   uint32_t oat_file_end = ART_BASE_ADDRESS + (2 * kElfSegmentAlignment + 2 * KB);
76   ImageSection sections[ImageHeader::kSectionCount];
77   uint32_t image_reservation_size = RoundUp(oat_file_end - image_begin, kElfSegmentAlignment);
78   ImageHeader image_header(image_reservation_size,
79                            /*component_count=*/ 1u,
80                            image_begin,
81                            image_size_,
82                            sections,
83                            image_roots,
84                            oat_checksum,
85                            oat_file_begin,
86                            oat_data_begin,
87                            oat_data_end,
88                            oat_file_end,
89                            /*boot_image_begin=*/ 0u,
90                            /*boot_image_size=*/ 0u,
91                            /*boot_image_component_count=*/ 0u,
92                            /*boot_image_checksum=*/ 0u,
93                            kRuntimePointerSize);
94   ASSERT_TRUE(image_header.IsValid());
95 
96   // Please note that for the following condition to be true, the above values should be chosen in
97   // a way that image_reservation_size != RoundUp(image_size_, kElfSegmentAlignment).
98   ASSERT_TRUE(!image_header.IsAppImage());
99 
100   char* magic = const_cast<char*>(image_header.GetMagic());
101   strcpy(magic, "");  // bad magic
102   ASSERT_FALSE(image_header.IsValid());
103   strcpy(magic, "art\n000");  // bad version
104   ASSERT_FALSE(image_header.IsValid());
105 }
106 
107 // Test that pointer to quick code is the same in
108 // a default method of an interface and in a copied method
109 // of a class which implements the interface. This should be true
110 // only if the copied method and the origin method are located in the
111 // same oat file.
TEST_F(ImageTest,TestDefaultMethods)112 TEST_F(ImageTest, TestDefaultMethods) {
113   // TODO(b/376621099): investigate LUCI failures (timeouts?) and re-enable this test.
114   // This is probably not related to riscv64 arch, but a combination of riscv64 and running
115   // on VM, but we don't use TEST_DISABLED_ON_VM to keep running it on other VM builders.
116   TEST_DISABLED_FOR_RISCV64();
117 
118   // Use this test to compile managed code to catch crashes when compiling the boot class path.
119   // This test already needs to compile some managed methods and by compiling with "speed" we
120   // avoid the need to create a specialized profile for the "speed-profile" compilation.
121   // (Using "speed" shall compile most methods. We could compile more with "everything".)
122   SetCompilerFilter(CompilerFilter::kSpeed);
123   CompilationHelper helper;
124   Compile(ImageHeader::kStorageModeUncompressed,
125           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
126           helper,
127           "DefaultMethods",
128           {"LIface;", "LImpl;", "LIterableBase;"});
129 
130   PointerSize pointer_size = class_linker_->GetImagePointerSize();
131   Thread* self = Thread::Current();
132   ScopedObjectAccess soa(self);
133 
134   // Test the pointer to quick code is the same in origin method
135   // and in the copied method from the same oat file.
136   ObjPtr<mirror::Class> iface_klass =
137       class_linker_->LookupClass(self, "LIface;", /*class_loader=*/ nullptr);
138   ASSERT_NE(nullptr, iface_klass);
139   ArtMethod* origin = iface_klass->FindInterfaceMethod("defaultMethod", "()V", pointer_size);
140   ASSERT_NE(nullptr, origin);
141   ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iface_klass);
142   const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
143   // The origin method should have a pointer to quick code
144   ASSERT_NE(nullptr, code);
145   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
146   ObjPtr<mirror::Class> impl_klass =
147       class_linker_->LookupClass(self, "LImpl;", /*class_loader=*/ nullptr);
148   ASSERT_NE(nullptr, impl_klass);
149   ArtMethod* copied = FindCopiedMethod(origin, impl_klass);
150   ASSERT_NE(nullptr, copied);
151   // the copied method should have pointer to the same quick code as the origin method
152   ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size));
153 
154   // Test the origin method has pointer to quick code
155   // but the copied method has pointer to interpreter
156   // because these methods are in different oat files.
157   ObjPtr<mirror::Class> iterable_klass =
158       class_linker_->LookupClass(self, "Ljava/lang/Iterable;", /*class_loader=*/ nullptr);
159   ASSERT_NE(nullptr, iterable_klass);
160   origin = iterable_klass->FindClassMethod(
161       "forEach", "(Ljava/util/function/Consumer;)V", pointer_size);
162   ASSERT_NE(nullptr, origin);
163   ASSERT_FALSE(origin->IsDirect());
164   ASSERT_OBJ_PTR_EQ(origin->GetDeclaringClass(), iterable_klass);
165   code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
166   // the origin method should have a pointer to quick code
167   ASSERT_NE(nullptr, code);
168   ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code));
169   ObjPtr<mirror::Class> iterablebase_klass =
170       class_linker_->LookupClass(self, "LIterableBase;", /*class_loader=*/ nullptr);
171   ASSERT_NE(nullptr, iterablebase_klass);
172   copied = FindCopiedMethod(origin, iterablebase_klass);
173   ASSERT_NE(nullptr, copied);
174   code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
175   // the copied method should have a pointer to interpreter
176   ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code));
177 }
178 
179 // Regression test for dex2oat crash for soft verification failure during
180 // class initialization check from the transactional interpreter while
181 // running the class initializer for another class.
TEST_F(ImageTest,TestSoftVerificationFailureDuringClassInitialization)182 TEST_F(ImageTest, TestSoftVerificationFailureDuringClassInitialization) {
183   CompilationHelper helper;
184   Compile(ImageHeader::kStorageModeUncompressed,
185           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
186           helper,
187           "VerifySoftFailDuringClinit",
188           /*image_classes=*/ {"LClassToInitialize;"},
189           /*image_classes_failing_aot_clinit=*/ {"LClassToInitialize;"});
190 }
191 
TEST_F(ImageTest,TestImageClassWithArrayClassWithUnresolvedComponent)192 TEST_F(ImageTest, TestImageClassWithArrayClassWithUnresolvedComponent) {
193   CompilationHelper helper;
194   Compile(ImageHeader::kStorageModeUncompressed,
195           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
196           helper,
197           "ArrayClassWithUnresolvedComponent",
198           /*image_classes=*/ {"LClassWithStatic;",
199                               "LClassWithStaticConst;",
200                               "[LClassWithMissingInterface;",
201                               "[[LClassWithMissingInterface;",
202                               "[LClassWithMissingSuper",
203                               "[[LClassWithMissingSuper"},
204           /*image_classes_failing_aot_clinit=*/ {
205                               "LClassWithStatic;",
206                               "LClassWithStaticConst;"},
207           /*image_classes_failing_resolution=*/ {
208                               "[LClassWithMissingInterface;",
209                               "[[LClassWithMissingInterface;",
210                               "[LClassWithMissingSuper",
211                               "[[LClassWithMissingSuper"});
212 }
213 
TEST_F(ImageTest,TestSuperWithAccessChecks)214 TEST_F(ImageTest, TestSuperWithAccessChecks) {
215   CompilationHelper helper;
216   Compile(ImageHeader::kStorageModeUncompressed,
217           /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
218           helper,
219           "SuperWithAccessChecks",
220           /*image_classes=*/ {"LSubClass;", "LImplementsClass;"},
221           /*image_classes_failing_aot_clinit=*/ {"LSubClass;", "LImplementsClass;"});
222 }
223 
224 // Regression test for b/297453985, where we used to generate a bogus image
225 // checksum.
TEST_F(ImageTest,ImageChecksum)226 TEST_F(ImageTest, ImageChecksum) {
227   uint32_t image_begin = ART_BASE_ADDRESS;
228   uint32_t image_roots = ART_BASE_ADDRESS + (1 * KB);
229   ImageSection sections[ImageHeader::kSectionCount];
230   // We require bitmap section to be at least kElfSegmentAlignment.
231   sections[ImageHeader::kSectionImageBitmap] = ImageSection(0, kElfSegmentAlignment);
232   ImageHeader image_header(/*image_reservation_size=*/ kElfSegmentAlignment,
233                            /*component_count=*/ 1u,
234                            image_begin,
235                            /*image_size=*/ sizeof(ImageHeader),
236                            sections,
237                            image_roots,
238                            /*oat_checksum=*/ 0u,
239                            /*oat_file_begin=*/ 0u,
240                            /*oat_data_begin=*/ 0u,
241                            /*oat_data_end=*/ 0u,
242                            /*oat_file_end=*/ 0u,
243                            /*boot_image_begin=*/ 0u,
244                            /*boot_image_size=*/ 0u,
245                            /*boot_image_component_count=*/ 0u,
246                            /*boot_image_checksum=*/ 0u,
247                            kRuntimePointerSize);
248     ASSERT_TRUE(image_header.IsValid());
249 
250     std::string error_msg;
251     ImageFileGuard image_file;
252     ScratchFile location;
253     image_file.reset(OS::CreateEmptyFile(location.GetFilename().c_str()));
254     const uint8_t* data = reinterpret_cast<const uint8_t*>(&image_header);
255     std::unique_ptr<uint8_t> bitmap(new uint8_t[kElfSegmentAlignment]);
256     memset(bitmap.get(), 0, kElfSegmentAlignment);
257     ASSERT_EQ(image_header.GetImageChecksum(), 0u);
258     ASSERT_TRUE(image_header.WriteData(
259         image_file,
260         data,
261         bitmap.get(),
262         ImageHeader::kStorageModeUncompressed,
263         /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
264         /*update_checksum=*/ true,
265         &error_msg)) << error_msg;
266 
267     uint32_t first_checksum = image_header.GetImageChecksum();
268     // Reset the image checksum, `WriteData` updated it.
269     image_header.SetImageChecksum(0u);
270 
271     // Change the header to ensure the checksum will be different.
272     image_header.SetOatChecksum(0xFFFF);
273 
274     ASSERT_TRUE(image_header.WriteData(
275         image_file,
276         data,
277         bitmap.get(),
278         ImageHeader::kStorageModeUncompressed,
279         /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
280         /*update_checksum=*/ true,
281         &error_msg)) << error_msg;
282 
283     ASSERT_NE(first_checksum, image_header.GetImageChecksum());
284 }
285 
286 }  // namespace linker
287 }  // namespace art
288