xref: /aosp_15_r20/art/dex2oat/linker/oat_writer_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 "android-base/stringprintf.h"
18 
19 #include "arch/instruction_set_features.h"
20 #include "art_method-inl.h"
21 #include "base/file_utils.h"
22 #include "base/pointer_size.h"
23 #include "base/stl_util.h"
24 #include "base/unix_file/fd_file.h"
25 #include "class_linker.h"
26 #include "common_compiler_driver_test.h"
27 #include "compiler.h"
28 #include "debug/method_debug_info.h"
29 #include "dex/class_accessor-inl.h"
30 #include "dex/dex_file_loader.h"
31 #include "dex/quick_compiler_callbacks.h"
32 #include "dex/test_dex_file_builder.h"
33 #include "dex/verification_results.h"
34 #include "driver/compiled_method-inl.h"
35 #include "driver/compiler_driver.h"
36 #include "driver/compiler_options.h"
37 #include "entrypoints/quick/quick_entrypoints.h"
38 #include "linker/elf_writer.h"
39 #include "linker/elf_writer_quick.h"
40 #include "linker/multi_oat_relative_patcher.h"
41 #include "mirror/class-inl.h"
42 #include "mirror/object-inl.h"
43 #include "mirror/object_array-inl.h"
44 #include "oat/oat.h"
45 #include "oat/oat_file-inl.h"
46 #include "oat_writer.h"
47 #include "profile/profile_compilation_info.h"
48 #include "scoped_thread_state_change-inl.h"
49 #include "stream/buffered_output_stream.h"
50 #include "stream/file_output_stream.h"
51 #include "stream/vector_output_stream.h"
52 #include "vdex_file.h"
53 
54 namespace art {
55 namespace linker {
56 
57 class OatTest : public CommonCompilerDriverTest {
58  protected:
59   static const bool kCompile = false;  // DISABLED_ due to the time to compile libcore
60 
CheckMethod(ArtMethod * method,const OatFile::OatMethod & oat_method,const DexFile & dex_file)61   void CheckMethod(ArtMethod* method,
62                    const OatFile::OatMethod& oat_method,
63                    const DexFile& dex_file)
64       REQUIRES_SHARED(Locks::mutator_lock_) {
65     const CompiledMethod* compiled_method =
66         compiler_driver_->GetCompiledMethod(MethodReference(&dex_file,
67                                                             method->GetDexMethodIndex()));
68 
69     if (compiled_method == nullptr) {
70       EXPECT_TRUE(oat_method.GetQuickCode() == nullptr) << method->PrettyMethod() << " "
71                                                         << oat_method.GetQuickCode();
72       EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U);
73       EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
74       EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
75     } else {
76       const void* quick_oat_code = oat_method.GetQuickCode();
77       EXPECT_TRUE(quick_oat_code != nullptr) << method->PrettyMethod();
78       uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2);
79       quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
80       ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
81       EXPECT_FALSE(quick_code.empty());
82       size_t code_size = quick_code.size() * sizeof(quick_code[0]);
83       EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size))
84           << method->PrettyMethod() << " " << code_size;
85       CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size));
86     }
87   }
88 
SetupCompiler(const std::vector<std::string> & compiler_options)89   void SetupCompiler(const std::vector<std::string>& compiler_options) {
90     std::string error_msg;
91     if (!compiler_options_->ParseCompilerOptions(compiler_options,
92                                                  /*ignore_unrecognized=*/ false,
93                                                  &error_msg)) {
94       LOG(FATAL) << error_msg;
95       UNREACHABLE();
96     }
97     callbacks_.reset(new QuickCompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp));
98     callbacks_->SetVerificationResults(verification_results_.get());
99     Runtime::Current()->SetCompilerCallbacks(callbacks_.get());
100   }
101 
WriteElf(File * vdex_file,File * oat_file,const std::vector<const DexFile * > & dex_files,SafeMap<std::string,std::string> & key_value_store,bool verify)102   bool WriteElf(File* vdex_file,
103                 File* oat_file,
104                 const std::vector<const DexFile*>& dex_files,
105                 SafeMap<std::string, std::string>& key_value_store,
106                 bool verify) {
107     TimingLogger timings("WriteElf", false, false);
108     ClearBootImageOption();
109     OatWriter oat_writer(*compiler_options_, &timings, /*profile_compilation_info*/nullptr);
110     for (const DexFile* dex_file : dex_files) {
111       if (!oat_writer.AddRawDexFileSource(dex_file->GetContainer(),
112                                           dex_file->Begin(),
113                                           dex_file->GetLocation().c_str(),
114                                           dex_file->GetLocationChecksum())) {
115         return false;
116       }
117     }
118     return DoWriteElf(
119         vdex_file, oat_file, oat_writer, key_value_store, verify, CopyOption::kOnlyIfCompressed);
120   }
121 
WriteElf(File * vdex_file,File * oat_file,const std::vector<const char * > & dex_filenames,SafeMap<std::string,std::string> & key_value_store,bool verify,CopyOption copy,ProfileCompilationInfo * profile_compilation_info)122   bool WriteElf(File* vdex_file,
123                 File* oat_file,
124                 const std::vector<const char*>& dex_filenames,
125                 SafeMap<std::string, std::string>& key_value_store,
126                 bool verify,
127                 CopyOption copy,
128                 ProfileCompilationInfo* profile_compilation_info) {
129     TimingLogger timings("WriteElf", false, false);
130     ClearBootImageOption();
131     OatWriter oat_writer(*compiler_options_, &timings, profile_compilation_info);
132     for (const char* dex_filename : dex_filenames) {
133       if (!oat_writer.AddDexFileSource(dex_filename, dex_filename)) {
134         return false;
135       }
136     }
137     return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
138   }
139 
WriteElf(File * vdex_file,File * oat_file,File && dex_file_fd,const char * location,SafeMap<std::string,std::string> & key_value_store,bool verify,CopyOption copy,ProfileCompilationInfo * profile_compilation_info=nullptr)140   bool WriteElf(File* vdex_file,
141                 File* oat_file,
142                 File&& dex_file_fd,
143                 const char* location,
144                 SafeMap<std::string, std::string>& key_value_store,
145                 bool verify,
146                 CopyOption copy,
147                 ProfileCompilationInfo* profile_compilation_info = nullptr) {
148     TimingLogger timings("WriteElf", false, false);
149     ClearBootImageOption();
150     OatWriter oat_writer(*compiler_options_, &timings, profile_compilation_info);
151     if (!oat_writer.AddDexFileSource(std::move(dex_file_fd), location)) {
152       return false;
153     }
154     return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
155   }
156 
DoWriteElf(File * vdex_file,File * oat_file,OatWriter & oat_writer,SafeMap<std::string,std::string> & key_value_store,bool verify,CopyOption copy)157   bool DoWriteElf(File* vdex_file,
158                   File* oat_file,
159                   OatWriter& oat_writer,
160                   SafeMap<std::string, std::string>& key_value_store,
161                   bool verify,
162                   CopyOption copy) {
163     std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
164         compiler_driver_->GetCompilerOptions(),
165         oat_file);
166     elf_writer->Start();
167     OutputStream* oat_rodata = elf_writer->StartRoData();
168     std::vector<MemMap> opened_dex_files_maps;
169     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
170     if (!oat_writer.WriteAndOpenDexFiles(
171         vdex_file,
172         verify,
173         /*use_existing_vdex=*/ false,
174         copy,
175         &opened_dex_files_maps,
176         &opened_dex_files)) {
177       return false;
178     }
179 
180     Runtime* runtime = Runtime::Current();
181     ClassLinker* const class_linker = runtime->GetClassLinker();
182     std::vector<const DexFile*> dex_files;
183     for (const std::unique_ptr<const DexFile>& dex_file : opened_dex_files) {
184       dex_files.push_back(dex_file.get());
185       ScopedObjectAccess soa(Thread::Current());
186       class_linker->RegisterDexFile(*dex_file, nullptr);
187     }
188     MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(),
189                                     compiler_options_->GetInstructionSetFeatures(),
190                                     compiler_driver_->GetCompiledMethodStorage());
191     if (!oat_writer.StartRoData(dex_files, oat_rodata, &key_value_store)) {
192       return false;
193     }
194     oat_writer.Initialize(
195         compiler_driver_.get(), verification_results_.get(), /*image_writer=*/ nullptr, dex_files);
196     if (!oat_writer.FinishVdexFile(vdex_file, /*verifier_deps=*/ nullptr)) {
197       return false;
198     }
199     oat_writer.PrepareLayout(&patcher);
200     elf_writer->PrepareDynamicSection(oat_writer.GetOatHeader().GetExecutableOffset(),
201                                       oat_writer.GetCodeSize(),
202                                       oat_writer.GetDataImgRelRoSize(),
203                                       oat_writer.GetDataImgRelRoAppImageOffset(),
204                                       oat_writer.GetBssSize(),
205                                       oat_writer.GetBssMethodsOffset(),
206                                       oat_writer.GetBssRootsOffset(),
207                                       oat_writer.GetVdexSize());
208 
209 
210     if (!oat_writer.WriteRodata(oat_rodata)) {
211       return false;
212     }
213     elf_writer->EndRoData(oat_rodata);
214 
215     OutputStream* text = elf_writer->StartText();
216     if (!oat_writer.WriteCode(text)) {
217       return false;
218     }
219     elf_writer->EndText(text);
220 
221     if (oat_writer.GetDataImgRelRoSize() != 0u) {
222       OutputStream* data_img_rel_ro = elf_writer->StartDataImgRelRo();
223       if (!oat_writer.WriteDataImgRelRo(data_img_rel_ro)) {
224         return false;
225       }
226       elf_writer->EndDataImgRelRo(data_img_rel_ro);
227     }
228 
229     if (!oat_writer.WriteHeader(elf_writer->GetStream())) {
230       return false;
231     }
232 
233     elf_writer->WriteDynamicSection();
234     elf_writer->WriteDebugInfo(oat_writer.GetDebugInfo());
235 
236     if (!elf_writer->End()) {
237       return false;
238     }
239 
240     for (MemMap& map : opened_dex_files_maps) {
241       opened_dex_files_maps_.emplace_back(std::move(map));
242     }
243     for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files) {
244       opened_dex_files_.emplace_back(dex_file.release());
245     }
246     return true;
247   }
248 
CheckOatWriteResult(ScratchFile & oat_file,ScratchFile & vdex_file,std::vector<std::unique_ptr<const DexFile>> & input_dexfiles,const unsigned int expected_oat_dexfile_count,bool low_4gb)249   void CheckOatWriteResult(ScratchFile& oat_file,
250                            ScratchFile& vdex_file,
251                            std::vector<std::unique_ptr<const DexFile>>& input_dexfiles,
252                            const unsigned int expected_oat_dexfile_count,
253                            bool low_4gb) {
254     ASSERT_EQ(expected_oat_dexfile_count, input_dexfiles.size());
255 
256     std::string error_msg;
257     std::unique_ptr<OatFile> opened_oat_file(OatFile::Open(/*zip_fd=*/ -1,
258                                                            oat_file.GetFilename(),
259                                                            oat_file.GetFilename(),
260                                                            /*executable=*/ false,
261                                                            low_4gb,
262                                                            &error_msg));
263     ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
264     ASSERT_EQ(expected_oat_dexfile_count, opened_oat_file->GetOatDexFiles().size());
265 
266     if (low_4gb) {
267       uintptr_t begin = reinterpret_cast<uintptr_t>(opened_oat_file->Begin());
268       EXPECT_EQ(begin, static_cast<uint32_t>(begin));
269     }
270 
271     for (uint32_t i = 0; i <  input_dexfiles.size(); i++) {
272       const std::unique_ptr<const DexFile>& dex_file_data = input_dexfiles[i];
273       std::unique_ptr<const DexFile> opened_dex_file =
274           opened_oat_file->GetOatDexFiles()[i]->OpenDexFile(&error_msg);
275 
276       ASSERT_EQ(opened_oat_file->GetOatDexFiles()[i]->GetDexFileLocationChecksum(),
277                 dex_file_data->GetHeader().checksum_);
278 
279       ASSERT_EQ(dex_file_data->GetHeader().file_size_, opened_dex_file->GetHeader().file_size_);
280       ASSERT_EQ(0, memcmp(&dex_file_data->GetHeader(),
281                           &opened_dex_file->GetHeader(),
282                           dex_file_data->GetHeader().file_size_));
283       ASSERT_EQ(dex_file_data->GetLocation(), opened_dex_file->GetLocation());
284     }
285 
286     int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
287     ASSERT_GE(actual_vdex_size, 0);
288     ASSERT_EQ(dchecked_integral_cast<uint64_t>(actual_vdex_size),
289               opened_oat_file->GetVdexFile()->GetComputedFileSize());
290   }
291 
292   void TestDexFileInput(bool verify, bool low_4gb, bool use_profile);
293   void TestZipFileInput(bool verify, CopyOption copy);
294   void TestZipFileInputWithEmptyDex();
295 
296   std::unique_ptr<QuickCompilerCallbacks> callbacks_;
297 
298   std::vector<MemMap> opened_dex_files_maps_;
299   std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
300 };
301 
302 class ZipBuilder {
303  public:
ZipBuilder(File * zip_file)304   explicit ZipBuilder(File* zip_file) : zip_file_(zip_file) { }
305 
AddFile(const char * location,const void * data,size_t size)306   bool AddFile(const char* location, const void* data, size_t size) {
307     off_t offset = lseek(zip_file_->Fd(), 0, SEEK_CUR);
308     if (offset == static_cast<off_t>(-1)) {
309       return false;
310     }
311 
312     ZipFileHeader file_header;
313     file_header.crc32 = crc32(0u, reinterpret_cast<const Bytef*>(data), size);
314     file_header.compressed_size = size;
315     file_header.uncompressed_size = size;
316     file_header.filename_length = strlen(location);
317 
318     if (!zip_file_->WriteFully(&file_header, sizeof(file_header)) ||
319         !zip_file_->WriteFully(location, file_header.filename_length) ||
320         !zip_file_->WriteFully(data, size)) {
321       return false;
322     }
323 
324     CentralDirectoryFileHeader cdfh;
325     cdfh.crc32 = file_header.crc32;
326     cdfh.compressed_size = size;
327     cdfh.uncompressed_size = size;
328     cdfh.filename_length = file_header.filename_length;
329     cdfh.relative_offset_of_local_file_header = offset;
330     file_data_.push_back(FileData { cdfh, location });
331     return true;
332   }
333 
Finish()334   bool Finish() {
335     off_t offset = lseek(zip_file_->Fd(), 0, SEEK_CUR);
336     if (offset == static_cast<off_t>(-1)) {
337       return false;
338     }
339 
340     size_t central_directory_size = 0u;
341     for (const FileData& file_data : file_data_) {
342       if (!zip_file_->WriteFully(&file_data.cdfh, sizeof(file_data.cdfh)) ||
343           !zip_file_->WriteFully(file_data.location, file_data.cdfh.filename_length)) {
344         return false;
345       }
346       central_directory_size += sizeof(file_data.cdfh) + file_data.cdfh.filename_length;
347     }
348     EndOfCentralDirectoryRecord eocd_record;
349     eocd_record.number_of_central_directory_records_on_this_disk = file_data_.size();
350     eocd_record.total_number_of_central_directory_records = file_data_.size();
351     eocd_record.size_of_central_directory = central_directory_size;
352     eocd_record.offset_of_start_of_central_directory = offset;
353     return
354         zip_file_->WriteFully(&eocd_record, sizeof(eocd_record)) &&
355         zip_file_->Flush() == 0;
356   }
357 
358  private:
359   struct PACKED(1) ZipFileHeader {
360     uint32_t signature = 0x04034b50;
361     uint16_t version_needed_to_extract = 10;
362     uint16_t general_purpose_bit_flag = 0;
363     uint16_t compression_method = 0;            // 0 = store only.
364     uint16_t file_last_modification_time = 0u;
365     uint16_t file_last_modification_date = 0u;
366     uint32_t crc32;
367     uint32_t compressed_size;
368     uint32_t uncompressed_size;
369     uint16_t filename_length;
370     uint16_t extra_field_length = 0u;           // No extra fields.
371   };
372 
373   struct PACKED(1) CentralDirectoryFileHeader {
374     uint32_t signature = 0x02014b50;
375     uint16_t version_made_by = 10;
376     uint16_t version_needed_to_extract = 10;
377     uint16_t general_purpose_bit_flag = 0;
378     uint16_t compression_method = 0;            // 0 = store only.
379     uint16_t file_last_modification_time = 0u;
380     uint16_t file_last_modification_date = 0u;
381     uint32_t crc32;
382     uint32_t compressed_size;
383     uint32_t uncompressed_size;
384     uint16_t filename_length;
385     uint16_t extra_field_length = 0u;           // No extra fields.
386     uint16_t file_comment_length = 0u;          // No file comment.
387     uint16_t disk_number_where_file_starts = 0u;
388     uint16_t internal_file_attributes = 0u;
389     uint32_t external_file_attributes = 0u;
390     uint32_t relative_offset_of_local_file_header;
391   };
392 
393   struct PACKED(1) EndOfCentralDirectoryRecord {
394     uint32_t signature = 0x06054b50;
395     uint16_t number_of_this_disk = 0u;
396     uint16_t disk_where_central_directory_starts = 0u;
397     uint16_t number_of_central_directory_records_on_this_disk;
398     uint16_t total_number_of_central_directory_records;
399     uint32_t size_of_central_directory;
400     uint32_t offset_of_start_of_central_directory;
401     uint16_t comment_length = 0u;               // No file comment.
402   };
403 
404   struct FileData {
405     CentralDirectoryFileHeader cdfh;
406     const char* location;
407   };
408 
409   File* zip_file_;
410   std::vector<FileData> file_data_;
411 };
412 
TEST_F(OatTest,WriteRead)413 TEST_F(OatTest, WriteRead) {
414   TimingLogger timings("OatTest::WriteRead", false, false);
415   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
416 
417   std::string error_msg;
418   SetupCompiler(std::vector<std::string>());
419 
420   jobject class_loader = nullptr;
421   if (kCompile) {
422     TimingLogger timings2("OatTest::WriteRead", false, false);
423     CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2);
424   }
425 
426   ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
427   SafeMap<std::string, std::string> key_value_store;
428   key_value_store.Put(OatHeader::kBootClassPathChecksumsKey, "testkey");
429   bool success = WriteElf(tmp_vdex.GetFile(),
430                           tmp_oat.GetFile(),
431                           class_linker->GetBootClassPath(),
432                           key_value_store,
433                           false);
434   ASSERT_TRUE(success);
435 
436   if (kCompile) {  // OatWriter strips the code, regenerate to compare
437     CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
438   }
439   std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
440                                                   tmp_oat.GetFilename(),
441                                                   tmp_oat.GetFilename(),
442                                                   /*executable=*/ false,
443                                                   /*low_4gb=*/ true,
444                                                   &error_msg));
445   ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
446   const OatHeader& oat_header = oat_file->GetOatHeader();
447   ASSERT_TRUE(oat_header.IsValid());
448   ASSERT_EQ(class_linker->GetBootClassPath().size(), oat_header.GetDexFileCount());  // core
449   ASSERT_TRUE(oat_header.GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey) != nullptr);
450   ASSERT_STREQ("testkey", oat_header.GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey));
451 
452   ASSERT_TRUE(java_lang_dex_file_ != nullptr);
453   const DexFile& dex_file = *java_lang_dex_file_;
454   const OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str());
455   ASSERT_TRUE(oat_dex_file != nullptr);
456   CHECK_EQ(dex_file.GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
457   ScopedObjectAccess soa(Thread::Current());
458   auto pointer_size = class_linker->GetImagePointerSize();
459   for (ClassAccessor accessor : dex_file.GetClasses()) {
460     size_t num_virtual_methods = accessor.NumVirtualMethods();
461 
462     const char* descriptor = accessor.GetDescriptor();
463     ObjPtr<mirror::Class> klass = FindClass(descriptor, ScopedNullHandle<mirror::ClassLoader>());
464 
465     const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(accessor.GetClassDefIndex());
466     CHECK_EQ(ClassStatus::kNotReady, oat_class.GetStatus()) << descriptor;
467     CHECK_EQ(kCompile ? OatClassType::kAllCompiled : OatClassType::kNoneCompiled,
468              oat_class.GetType()) << descriptor;
469 
470     size_t method_index = 0;
471     for (auto& m : klass->GetDirectMethods(pointer_size)) {
472       CheckMethod(&m, oat_class.GetOatMethod(method_index), dex_file);
473       ++method_index;
474     }
475     size_t visited_virtuals = 0;
476     // TODO We should also check copied methods in this test.
477     for (auto& m : klass->GetDeclaredVirtualMethods(pointer_size)) {
478       if (!klass->IsInterface()) {
479         EXPECT_FALSE(m.IsCopied());
480       }
481       CheckMethod(&m, oat_class.GetOatMethod(method_index), dex_file);
482       ++method_index;
483       ++visited_virtuals;
484     }
485     EXPECT_EQ(visited_virtuals, num_virtual_methods);
486   }
487 }
488 
TEST_F(OatTest,OatHeaderSizeCheck)489 TEST_F(OatTest, OatHeaderSizeCheck) {
490   // If this test is failing and you have to update these constants,
491   // it is time to update OatHeader::kOatVersion
492   EXPECT_EQ(68U, sizeof(OatHeader));
493   EXPECT_EQ(4U, sizeof(OatMethodOffsets));
494   EXPECT_EQ(4U, sizeof(OatQuickMethodHeader));
495   EXPECT_EQ(173 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
496             sizeof(QuickEntryPoints));
497 }
498 
TEST_F(OatTest,OatHeaderIsValid)499 TEST_F(OatTest, OatHeaderIsValid) {
500   InstructionSet insn_set = InstructionSet::kX86;
501   std::string error_msg;
502   std::unique_ptr<const InstructionSetFeatures> insn_features(
503     InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
504   ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
505   std::unique_ptr<OatHeader> oat_header(OatHeader::Create(insn_set,
506                                                           insn_features.get(),
507                                                           0u,
508                                                           nullptr));
509   ASSERT_NE(oat_header.get(), nullptr);
510   ASSERT_TRUE(oat_header->IsValid());
511 
512   char* magic = const_cast<char*>(oat_header->GetMagic());
513   strcpy(magic, "");  // bad magic
514   ASSERT_FALSE(oat_header->IsValid());
515   strcpy(magic, "oat\n000");  // bad version
516   ASSERT_FALSE(oat_header->IsValid());
517 }
518 
TEST_F(OatTest,EmptyTextSection)519 TEST_F(OatTest, EmptyTextSection) {
520   TimingLogger timings("OatTest::EmptyTextSection", false, false);
521 
522   std::vector<std::string> compiler_options;
523   compiler_options.push_back("--compiler-filter=extract");
524   SetupCompiler(compiler_options);
525 
526   jobject class_loader;
527   {
528     ScopedObjectAccess soa(Thread::Current());
529     class_loader = LoadDex("Main");
530   }
531   ASSERT_TRUE(class_loader != nullptr);
532   std::vector<const DexFile*> dex_files = GetDexFiles(class_loader);
533   ASSERT_TRUE(!dex_files.empty());
534 
535   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
536   for (const DexFile* dex_file : dex_files) {
537     ScopedObjectAccess soa(Thread::Current());
538     class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader>(class_loader));
539   }
540   CompileAll(class_loader, dex_files, &timings);
541 
542   ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
543   SafeMap<std::string, std::string> key_value_store;
544   bool success = WriteElf(tmp_vdex.GetFile(),
545                           tmp_oat.GetFile(),
546                           dex_files,
547                           key_value_store,
548                           /*verify=*/ false);
549   ASSERT_TRUE(success);
550 
551   std::string error_msg;
552   std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
553                                                   tmp_oat.GetFilename(),
554                                                   tmp_oat.GetFilename(),
555                                                   /*executable=*/ false,
556                                                   /*low_4gb=*/ false,
557                                                   &error_msg));
558   ASSERT_TRUE(oat_file != nullptr);
559   EXPECT_LT(static_cast<size_t>(oat_file->Size()),
560             static_cast<size_t>(tmp_oat.GetFile()->GetLength()));
561 }
562 
MaybeModifyDexFileToFail(bool verify,std::unique_ptr<const DexFile> & data)563 static void MaybeModifyDexFileToFail(bool verify, std::unique_ptr<const DexFile>& data) {
564   // If in verify mode (= fail the verifier mode), make sure we fail early. We'll fail already
565   // because of the missing map, but that may lead to out of bounds reads.
566   if (verify) {
567     const_cast<DexFile::Header*>(&data->GetHeader())->checksum_++;
568   }
569 }
570 
TestDexFileInput(bool verify,bool low_4gb,bool use_profile)571 void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
572   TimingLogger timings("OatTest::DexFileInput", false, false);
573 
574   std::vector<const char*> input_filenames;
575   std::vector<std::unique_ptr<const DexFile>> input_dexfiles;
576   std::vector<const ScratchFile*> scratch_files;
577 
578   ScratchFile dex_file1;
579   TestDexFileBuilder builder1;
580   builder1.AddField("Lsome/TestClass;", "int", "someField");
581   builder1.AddMethod("Lsome/TestClass;", "()I", "foo");
582   std::unique_ptr<const DexFile> dex_file1_data = builder1.Build(dex_file1.GetFilename());
583 
584   MaybeModifyDexFileToFail(verify, dex_file1_data);
585 
586   bool success = dex_file1.GetFile()->WriteFully(&dex_file1_data->GetHeader(),
587                                                  dex_file1_data->GetHeader().file_size_);
588   ASSERT_TRUE(success);
589   success = dex_file1.GetFile()->Flush() == 0;
590   ASSERT_TRUE(success);
591   input_filenames.push_back(dex_file1.GetFilename().c_str());
592   input_dexfiles.push_back(std::move(dex_file1_data));
593   scratch_files.push_back(&dex_file1);
594 
595   ScratchFile dex_file2;
596   TestDexFileBuilder builder2;
597   builder2.AddField("Land/AnotherTestClass;", "boolean", "someOtherField");
598   builder2.AddMethod("Land/AnotherTestClass;", "()J", "bar");
599   std::unique_ptr<const DexFile> dex_file2_data = builder2.Build(dex_file2.GetFilename());
600 
601   MaybeModifyDexFileToFail(verify, dex_file2_data);
602 
603   success = dex_file2.GetFile()->WriteFully(&dex_file2_data->GetHeader(),
604                                             dex_file2_data->GetHeader().file_size_);
605   ASSERT_TRUE(success);
606   success = dex_file2.GetFile()->Flush() == 0;
607   ASSERT_TRUE(success);
608   input_filenames.push_back(dex_file2.GetFilename().c_str());
609   input_dexfiles.push_back(std::move(dex_file2_data));
610   scratch_files.push_back(&dex_file2);
611 
612   SafeMap<std::string, std::string> key_value_store;
613   {
614     // Test using the AddDexFileSource() interface with the dex files.
615     ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
616     std::unique_ptr<ProfileCompilationInfo>
617         profile_compilation_info(use_profile ? new ProfileCompilationInfo() : nullptr);
618     success = WriteElf(tmp_vdex.GetFile(),
619                        tmp_oat.GetFile(),
620                        input_filenames,
621                        key_value_store,
622                        verify,
623                        CopyOption::kOnlyIfCompressed,
624                        profile_compilation_info.get());
625 
626     // In verify mode, we expect failure.
627     if (verify) {
628       ASSERT_FALSE(success);
629       return;
630     }
631 
632     ASSERT_TRUE(success);
633 
634     CheckOatWriteResult(tmp_oat,
635                         tmp_vdex,
636                         input_dexfiles,
637                         /* oat_dexfile_count */ 2,
638                         low_4gb);
639   }
640 
641   {
642     // Test using the AddDexFileSource() interface with the dexfile1's fd.
643     // Only need one input dexfile.
644     std::vector<std::unique_ptr<const DexFile>> input_dexfiles2;
645     input_dexfiles2.push_back(std::move(input_dexfiles[0]));
646     const ScratchFile* dex_file = scratch_files[0];
647     File dex_file_fd(DupCloexec(dex_file->GetFd()), /*check_usage=*/ false);
648 
649     ASSERT_NE(-1, dex_file_fd.Fd());
650     ASSERT_EQ(0, lseek(dex_file_fd.Fd(), 0, SEEK_SET));
651 
652     ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
653     std::unique_ptr<ProfileCompilationInfo>
654         profile_compilation_info(use_profile ? new ProfileCompilationInfo() : nullptr);
655     success = WriteElf(tmp_vdex.GetFile(),
656                        tmp_oat.GetFile(),
657                        std::move(dex_file_fd),
658                        dex_file->GetFilename().c_str(),
659                        key_value_store,
660                        verify,
661                        CopyOption::kOnlyIfCompressed,
662                        profile_compilation_info.get());
663 
664     // In verify mode, we expect failure.
665     if (verify) {
666       ASSERT_FALSE(success);
667       return;
668     }
669 
670     ASSERT_TRUE(success);
671 
672     CheckOatWriteResult(tmp_oat,
673                         tmp_vdex,
674                         input_dexfiles2,
675                         /* oat_dexfile_count */ 1,
676                         low_4gb);
677   }
678 }
679 
TEST_F(OatTest,DexFileInputCheckOutput)680 TEST_F(OatTest, DexFileInputCheckOutput) {
681   TestDexFileInput(/*verify*/false, /*low_4gb*/false, /*use_profile*/false);
682 }
683 
TEST_F(OatTest,DexFileInputCheckOutputLow4GB)684 TEST_F(OatTest, DexFileInputCheckOutputLow4GB) {
685   TestDexFileInput(/*verify*/false, /*low_4gb*/true, /*use_profile*/false);
686 }
687 
TEST_F(OatTest,DexFileInputCheckVerifier)688 TEST_F(OatTest, DexFileInputCheckVerifier) {
689   TestDexFileInput(/*verify*/true, /*low_4gb*/false, /*use_profile*/false);
690 }
691 
TEST_F(OatTest,DexFileFailsVerifierWithLayout)692 TEST_F(OatTest, DexFileFailsVerifierWithLayout) {
693   TestDexFileInput(/*verify*/true, /*low_4gb*/false, /*use_profile*/true);
694 }
695 
TestZipFileInput(bool verify,CopyOption copy)696 void OatTest::TestZipFileInput(bool verify, CopyOption copy) {
697   TimingLogger timings("OatTest::DexFileInput", false, false);
698 
699   ScratchFile zip_file;
700   ZipBuilder zip_builder(zip_file.GetFile());
701 
702   ScratchFile dex_file1;
703   TestDexFileBuilder builder1;
704   builder1.AddField("Lsome/TestClass;", "long", "someField");
705   builder1.AddMethod("Lsome/TestClass;", "()D", "foo");
706   std::unique_ptr<const DexFile> dex_file1_data = builder1.Build(dex_file1.GetFilename());
707 
708   MaybeModifyDexFileToFail(verify, dex_file1_data);
709 
710   bool success = dex_file1.GetFile()->WriteFully(&dex_file1_data->GetHeader(),
711                                                  dex_file1_data->GetHeader().file_size_);
712   ASSERT_TRUE(success);
713   success = dex_file1.GetFile()->Flush() == 0;
714   ASSERT_TRUE(success);
715   success = zip_builder.AddFile("classes.dex",
716                                 &dex_file1_data->GetHeader(),
717                                 dex_file1_data->GetHeader().file_size_);
718   ASSERT_TRUE(success);
719 
720   ScratchFile dex_file2;
721   TestDexFileBuilder builder2;
722   builder2.AddField("Land/AnotherTestClass;", "boolean", "someOtherField");
723   builder2.AddMethod("Land/AnotherTestClass;", "()J", "bar");
724   std::unique_ptr<const DexFile> dex_file2_data = builder2.Build(dex_file2.GetFilename());
725 
726   MaybeModifyDexFileToFail(verify, dex_file2_data);
727 
728   success = dex_file2.GetFile()->WriteFully(&dex_file2_data->GetHeader(),
729                                             dex_file2_data->GetHeader().file_size_);
730   ASSERT_TRUE(success);
731   success = dex_file2.GetFile()->Flush() == 0;
732   ASSERT_TRUE(success);
733   success = zip_builder.AddFile("classes2.dex",
734                                 &dex_file2_data->GetHeader(),
735                                 dex_file2_data->GetHeader().file_size_);
736   ASSERT_TRUE(success);
737 
738   success = zip_builder.Finish();
739   ASSERT_TRUE(success) << strerror(errno);
740 
741   SafeMap<std::string, std::string> key_value_store;
742   {
743     // Test using the AddDexFileSource() interface with the zip file.
744     std::vector<const char*> input_filenames = { zip_file.GetFilename().c_str() };
745 
746     ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
747     success = WriteElf(tmp_vdex.GetFile(),
748                        tmp_oat.GetFile(),
749                        input_filenames,
750                        key_value_store,
751                        verify,
752                        copy,
753                        /*profile_compilation_info=*/ nullptr);
754 
755     if (verify) {
756       ASSERT_FALSE(success);
757     } else {
758       ASSERT_TRUE(success);
759 
760       std::string error_msg;
761       std::unique_ptr<OatFile> opened_oat_file(OatFile::Open(/*zip_fd=*/ -1,
762                                                              tmp_oat.GetFilename(),
763                                                              tmp_oat.GetFilename(),
764                                                              /*executable=*/ false,
765                                                              /*low_4gb=*/ false,
766                                                              &error_msg));
767       ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
768       ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size());
769       std::unique_ptr<const DexFile> opened_dex_file1 =
770           opened_oat_file->GetOatDexFiles()[0]->OpenDexFile(&error_msg);
771       std::unique_ptr<const DexFile> opened_dex_file2 =
772           opened_oat_file->GetOatDexFiles()[1]->OpenDexFile(&error_msg);
773 
774       ASSERT_EQ(dex_file1_data->GetHeader().file_size_, opened_dex_file1->GetHeader().file_size_);
775       ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
776                           &opened_dex_file1->GetHeader(),
777                           dex_file1_data->GetHeader().file_size_));
778       ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
779                 opened_dex_file1->GetLocation());
780 
781       ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
782       ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
783                           &opened_dex_file2->GetHeader(),
784                           dex_file2_data->GetHeader().file_size_));
785       ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
786                 opened_dex_file2->GetLocation());
787     }
788   }
789 
790   {
791     // Test using the AddDexFileSource() interface with the zip file handle.
792     File zip_fd(DupCloexec(zip_file.GetFd()), /*check_usage=*/ false);
793     ASSERT_NE(-1, zip_fd.Fd());
794     ASSERT_EQ(0, lseek(zip_fd.Fd(), 0, SEEK_SET));
795 
796     ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
797     success = WriteElf(tmp_vdex.GetFile(),
798                        tmp_oat.GetFile(),
799                        std::move(zip_fd),
800                        zip_file.GetFilename().c_str(),
801                        key_value_store,
802                        verify,
803                        copy);
804     if (verify) {
805       ASSERT_FALSE(success);
806     } else {
807       ASSERT_TRUE(success);
808 
809       std::string error_msg;
810       std::unique_ptr<OatFile> opened_oat_file(OatFile::Open(/*zip_fd=*/ -1,
811                                                              tmp_oat.GetFilename(),
812                                                              tmp_oat.GetFilename(),
813                                                              /*executable=*/ false,
814                                                              /*low_4gb=*/ false,
815                                                              &error_msg));
816       ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
817       ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size());
818       std::unique_ptr<const DexFile> opened_dex_file1 =
819           opened_oat_file->GetOatDexFiles()[0]->OpenDexFile(&error_msg);
820       std::unique_ptr<const DexFile> opened_dex_file2 =
821           opened_oat_file->GetOatDexFiles()[1]->OpenDexFile(&error_msg);
822 
823       ASSERT_EQ(dex_file1_data->GetHeader().file_size_, opened_dex_file1->GetHeader().file_size_);
824       ASSERT_EQ(0, memcmp(&dex_file1_data->GetHeader(),
825                           &opened_dex_file1->GetHeader(),
826                           dex_file1_data->GetHeader().file_size_));
827       ASSERT_EQ(DexFileLoader::GetMultiDexLocation(0, zip_file.GetFilename().c_str()),
828                 opened_dex_file1->GetLocation());
829 
830       ASSERT_EQ(dex_file2_data->GetHeader().file_size_, opened_dex_file2->GetHeader().file_size_);
831       ASSERT_EQ(0, memcmp(&dex_file2_data->GetHeader(),
832                           &opened_dex_file2->GetHeader(),
833                           dex_file2_data->GetHeader().file_size_));
834       ASSERT_EQ(DexFileLoader::GetMultiDexLocation(1, zip_file.GetFilename().c_str()),
835                 opened_dex_file2->GetLocation());
836     }
837   }
838 }
839 
TEST_F(OatTest,ZipFileInputCheckOutput)840 TEST_F(OatTest, ZipFileInputCheckOutput) {
841   TestZipFileInput(false, CopyOption::kOnlyIfCompressed);
842 }
843 
TEST_F(OatTest,ZipFileInputCheckOutputWithoutCopy)844 TEST_F(OatTest, ZipFileInputCheckOutputWithoutCopy) {
845   TestZipFileInput(false, CopyOption::kNever);
846 }
847 
TEST_F(OatTest,ZipFileInputCheckVerifier)848 TEST_F(OatTest, ZipFileInputCheckVerifier) {
849   TestZipFileInput(true, CopyOption::kOnlyIfCompressed);
850 }
851 
TestZipFileInputWithEmptyDex()852 void OatTest::TestZipFileInputWithEmptyDex() {
853   ScratchFile zip_file;
854   ZipBuilder zip_builder(zip_file.GetFile());
855   bool success = zip_builder.AddFile("classes.dex", nullptr, 0);
856   ASSERT_TRUE(success);
857   success = zip_builder.Finish();
858   ASSERT_TRUE(success) << strerror(errno);
859 
860   SafeMap<std::string, std::string> key_value_store;
861   std::vector<const char*> input_filenames = { zip_file.GetFilename().c_str() };
862   ScratchFile oat_file, vdex_file(oat_file, ".vdex");
863   std::unique_ptr<ProfileCompilationInfo> profile_compilation_info(new ProfileCompilationInfo());
864   success = WriteElf(vdex_file.GetFile(),
865                      oat_file.GetFile(),
866                      input_filenames,
867                      key_value_store,
868                      /*verify=*/ false,
869                      CopyOption::kOnlyIfCompressed,
870                      profile_compilation_info.get());
871   ASSERT_FALSE(success);
872 }
873 
TEST_F(OatTest,ZipFileInputWithEmptyDex)874 TEST_F(OatTest, ZipFileInputWithEmptyDex) {
875   TestZipFileInputWithEmptyDex();
876 }
877 
878 }  // namespace linker
879 }  // namespace art
880