diff options
author | 2018-02-07 13:47:17 -0800 | |
---|---|---|
committer | 2018-02-07 14:56:50 -0800 | |
commit | 05f90d133d288b524eaa9deacdc56e7d29ea9f99 (patch) | |
tree | 89153d3bccc0aba04423f5712fee09e768d5aa2c | |
parent | 0efe3243d4f1878e8220ff8bc469beee9ac90518 (diff) |
Avoid generating cdex for dex files with duplicate methods
For the cases where two different method have the same code item or
debug info, avoid generating cdex and write the input dex into the
oat file isntead.
Test: test-art-host-gtest
Bug: 72997076
Bug: 72100771
Bug: 72100668
Bug: 63756964
Change-Id: I5dfe2b47b2c908921c8421367536c2d950186ac6
-rw-r--r-- | dex2oat/dex2oat_test.cc | 108 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 26 | ||||
-rw-r--r-- | dexlayout/compact_dex_writer.cc | 59 | ||||
-rw-r--r-- | dexlayout/compact_dex_writer.h | 5 | ||||
-rw-r--r-- | dexlayout/dex_writer.cc | 12 | ||||
-rw-r--r-- | dexlayout/dex_writer.h | 7 | ||||
-rw-r--r-- | dexlayout/dexlayout.cc | 46 | ||||
-rw-r--r-- | dexlayout/dexlayout.h | 10 | ||||
-rw-r--r-- | dexlayout/dexlayout_test.cc | 11 | ||||
-rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 11 |
10 files changed, 246 insertions, 49 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 17a27f8567..d0b0d49a39 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -31,6 +31,7 @@ #include "base/mutex-inl.h" #include "bytecode_utils.h" #include "dex/art_dex_file_loader.h" +#include "dex/base64_test_util.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" @@ -1559,4 +1560,111 @@ TEST_F(Dex2oatTest, EmptyUncompressedDexTest) { ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg; } +// Dex file that has duplicate methods have different code items and debug info. +static const char kDuplicateMethodInputDex[] = + "ZGV4CjAzOQDEy8VPdj4qHpgPYFWtLCtOykfFP4kB8tGYDAAAcAAAAHhWNBIAAAAAAAAAANALAABI" + "AAAAcAAAAA4AAACQAQAABQAAAMgBAAANAAAABAIAABkAAABsAgAABAAAADQDAADgCAAAuAMAADgI" + "AABCCAAASggAAE8IAABcCAAAaggAAHkIAACICAAAlggAAKQIAACyCAAAwAgAAM4IAADcCAAA6ggA" + "APgIAAD7CAAA/wgAABcJAAAuCQAARQkAAFQJAAB4CQAAmAkAALsJAADSCQAA5gkAAPoJAAAVCgAA" + "KQoAADsKAABCCgAASgoAAFIKAABbCgAAZAoAAGwKAAB0CgAAfAoAAIQKAACMCgAAlAoAAJwKAACk" + "CgAArQoAALcKAADACgAAwwoAAMcKAADcCgAA6QoAAPEKAAD3CgAA/QoAAAMLAAAJCwAAEAsAABcL" + "AAAdCwAAIwsAACkLAAAvCwAANQsAADsLAABBCwAARwsAAE0LAABSCwAAWwsAAF4LAABoCwAAbwsA" + "ABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAC4AAAAwAAAA" + "DwAAAAkAAAAAAAAAEAAAAAoAAACoBwAALgAAAAwAAAAAAAAALwAAAAwAAACoBwAALwAAAAwAAACw" + "BwAAAgAJADUAAAACAAkANgAAAAIACQA3AAAAAgAJADgAAAACAAkAOQAAAAIACQA6AAAAAgAJADsA" + "AAACAAkAPAAAAAIACQA9AAAAAgAJAD4AAAACAAkAPwAAAAIACQBAAAAACwAHAEIAAAAAAAIAAQAA" + "AAAAAwAeAAAAAQACAAEAAAABAAMAHgAAAAIAAgAAAAAAAgACAAEAAAADAAIAAQAAAAMAAgAfAAAA" + "AwACACAAAAADAAIAIQAAAAMAAgAiAAAAAwACACMAAAADAAIAJAAAAAMAAgAlAAAAAwACACYAAAAD" + "AAIAJwAAAAMAAgAoAAAAAwACACkAAAADAAIAKgAAAAMABAA0AAAABwADAEMAAAAIAAIAAQAAAAoA" + "AgABAAAACgABADIAAAAKAAAARQAAAAAAAAAAAAAACAAAAAAAAAAdAAAAaAcAALYHAAAAAAAAAQAA" + "AAAAAAAIAAAAAAAAAB0AAAB4BwAAxAcAAAAAAAACAAAAAAAAAAgAAAAAAAAAHQAAAIgHAADSBwAA" + "AAAAAAMAAAAAAAAACAAAAAAAAAAdAAAAmAcAAPoHAAAAAAAAAAAAAAEAAAAAAAAArAYAADEAAAAa" + "AAMAaQAAABoABABpAAEAGgAHAGkABAAaAAgAaQAFABoACQBpAAYAGgAKAGkABwAaAAsAaQAIABoA" + "DABpAAkAGgANAGkACgAaAA4AaQALABoABQBpAAIAGgAGAGkAAwAOAAAAAQABAAEAAACSBgAABAAA" + "AHAQFQAAAA4ABAABAAIAAACWBgAAFwAAAGIADAAiAQoAcBAWAAEAGgICAG4gFwAhAG4gFwAxAG4Q" + "GAABAAwBbiAUABAADgAAAAEAAQABAAAAngYAAAQAAABwEBUAAAAOAAIAAQACAAAAogYAAAYAAABi" + "AAwAbiAUABAADgABAAEAAQAAAKgGAAAEAAAAcBAVAAAADgABAAEAAQAAALsGAAAEAAAAcBAVAAAA" + "DgABAAAAAQAAAL8GAAAGAAAAYgAAAHEQAwAAAA4AAQAAAAEAAADEBgAABgAAAGIAAQBxEAMAAAAO" + "AAEAAAABAAAA8QYAAAYAAABiAAIAcRABAAAADgABAAAAAQAAAPYGAAAGAAAAYgADAHEQAwAAAA4A" + "AQAAAAEAAADJBgAABgAAAGIABABxEAMAAAAOAAEAAAABAAAAzgYAAAYAAABiAAEAcRADAAAADgAB" + "AAAAAQAAANMGAAAGAAAAYgAGAHEQAwAAAA4AAQAAAAEAAADYBgAABgAAAGIABwBxEAMAAAAOAAEA" + "AAABAAAA3QYAAAYAAABiAAgAcRABAAAADgABAAAAAQAAAOIGAAAGAAAAYgAJAHEQAwAAAA4AAQAA" + "AAEAAADnBgAABgAAAGIACgBxEAMAAAAOAAEAAAABAAAA7AYAAAYAAABiAAsAcRABAAAADgABAAEA" + "AAAAAPsGAAAlAAAAcQAHAAAAcQAIAAAAcQALAAAAcQAMAAAAcQANAAAAcQAOAAAAcQAPAAAAcQAQ" + "AAAAcQARAAAAcQASAAAAcQAJAAAAcQAKAAAADgAnAA4AKQFFDgEWDwAhAA4AIwFFDloAEgAOABMA" + "DktLS0tLS0tLS0tLABEADgAuAA5aADIADloANgAOWgA6AA5aAD4ADloAQgAOWgBGAA5aAEoADloA" + "TgAOWgBSAA5aAFYADloAWgAOWgBeATQOPDw8PDw8PDw8PDw8AAIEAUYYAwIFAjEECEEXLAIFAjEE" + "CEEXKwIFAjEECEEXLQIGAUYcAxgAGAEYAgAAAAIAAAAMBwAAEgcAAAIAAAAMBwAAGwcAAAIAAAAM" + "BwAAJAcAAAEAAAAtBwAAPAcAAAAAAAAAAAAAAAAAAEgHAAAAAAAAAAAAAAAAAABUBwAAAAAAAAAA" + "AAAAAAAAYAcAAAAAAAAAAAAAAAAAAAEAAAAJAAAAAQAAAA0AAAACAACAgASsCAEIxAgAAAIAAoCA" + "BIQJAQicCQwAAgAACQEJAQkBCQEJAQkBCQEJAQkBCQEJAQkEiIAEuAcBgIAEuAkAAA4ABoCABNAJ" + "AQnoCQAJhAoACaAKAAm8CgAJ2AoACfQKAAmQCwAJrAsACcgLAAnkCwAJgAwACZwMAAm4DAg8Y2xp" + "bml0PgAGPGluaXQ+AANBQUEAC0hlbGxvIFdvcmxkAAxIZWxsbyBXb3JsZDEADUhlbGxvIFdvcmxk" + "MTAADUhlbGxvIFdvcmxkMTEADEhlbGxvIFdvcmxkMgAMSGVsbG8gV29ybGQzAAxIZWxsbyBXb3Js" + "ZDQADEhlbGxvIFdvcmxkNQAMSGVsbG8gV29ybGQ2AAxIZWxsbyBXb3JsZDcADEhlbGxvIFdvcmxk" + "OAAMSGVsbG8gV29ybGQ5AAFMAAJMTAAWTE1hbnlNZXRob2RzJFByaW50ZXIyOwAVTE1hbnlNZXRo" + "b2RzJFByaW50ZXI7ABVMTWFueU1ldGhvZHMkU3RyaW5nczsADUxNYW55TWV0aG9kczsAIkxkYWx2" + "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" + "YXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABVMamF2YS9pby9QcmludFN0" + "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5n" + "L1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsAEE1hbnlNZXRob2RzLmphdmEABVBy" + "aW50AAZQcmludDAABlByaW50MQAHUHJpbnQxMAAHUHJpbnQxMQAGUHJpbnQyAAZQcmludDMABlBy" + "aW50NAAGUHJpbnQ1AAZQcmludDYABlByaW50NwAGUHJpbnQ4AAZQcmludDkAB1ByaW50ZXIACFBy" + "aW50ZXIyAAdTdHJpbmdzAAFWAAJWTAATW0xqYXZhL2xhbmcvU3RyaW5nOwALYWNjZXNzRmxhZ3MA" + "BmFwcGVuZAAEYXJncwAEbWFpbgAEbXNnMAAEbXNnMQAFbXNnMTAABW1zZzExAARtc2cyAARtc2cz" + "AARtc2c0AARtc2c1AARtc2c2AARtc2c3AARtc2c4AARtc2c5AARuYW1lAANvdXQAB3ByaW50bG4A" + "AXMACHRvU3RyaW5nAAV2YWx1ZQBffn5EOHsibWluLWFwaSI6MTAwMDAsInNoYS0xIjoiZmViODZj" + "MDA2ZWZhY2YxZDc5ODRiODVlMTc5MGZlZjdhNzY3YWViYyIsInZlcnNpb24iOiJ2MS4xLjUtZGV2" + "In0AEAAAAAAAAAABAAAAAAAAAAEAAABIAAAAcAAAAAIAAAAOAAAAkAEAAAMAAAAFAAAAyAEAAAQA" + "AAANAAAABAIAAAUAAAAZAAAAbAIAAAYAAAAEAAAANAMAAAEgAAAUAAAAuAMAAAMgAAAUAAAAkgYA" + "AAQgAAAFAAAADAcAAAMQAAAEAAAAOQcAAAYgAAAEAAAAaAcAAAEQAAACAAAAqAcAAAAgAAAEAAAA" + "tgcAAAIgAABIAAAAOAgAAAAQAAABAAAA0AsAAAAAAAA="; + +static void WriteBase64ToFile(const char* base64, File* file) { + // Decode base64. + CHECK(base64 != nullptr); + size_t length; + std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length)); + CHECK(bytes != nullptr); + if (!file->WriteFully(bytes.get(), length)) { + PLOG(FATAL) << "Failed to write base64 as file"; + } +} + +TEST_F(Dex2oatTest, CompactDexGenerationFailure) { + ScratchFile temp_dex; + WriteBase64ToFile(kDuplicateMethodInputDex, temp_dex.GetFile()); + std::string out_dir = GetScratchDir(); + const std::string oat_filename = out_dir + "/base.oat"; + // The dex won't pass the method verifier, only use the verify filter. + GenerateOdexForTest(temp_dex.GetFilename(), + oat_filename, + CompilerFilter::Filter::kVerify, + { }, + true, // expect_success + false, // use_fd + [](const OatFile& o) { + CHECK(o.ContainsDexCode()); + }); + // Open our generated oat file. + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_filename.c_str(), + oat_filename.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + temp_dex.GetFilename().c_str(), + &error_msg)); + ASSERT_TRUE(odex_file != nullptr); + std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles(); + ASSERT_EQ(oat_dex_files.size(), 1u); + // The dexes should have failed to convert to compact dex. + for (const OatDexFile* oat_dex : oat_dex_files) { + std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg)); + ASSERT_TRUE(dex_file != nullptr) << error_msg; + ASSERT_TRUE(!dex_file->IsCompactDexFile()); + } +} + } // namespace art diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 0953e0813f..01125a178e 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -3597,17 +3597,21 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil options.compact_dex_level_ = compact_dex_level_; options.update_checksum_ = true; DexLayout dex_layout(options, profile_compilation_info_, /*file*/ nullptr, /*header*/ nullptr); - dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &dex_container_); - oat_dex_file->dex_sections_layout_ = dex_layout.GetSections(); - // Dex layout can affect the size of the dex file, so we update here what we have set - // when adding the dex file as a source. - const UnalignedDexFileHeader* header = - AsUnalignedDexFileHeader(dex_container_->GetMainSection()->Begin()); - oat_dex_file->dex_file_size_ = header->file_size_; - if (!WriteDexFile(out, - oat_dex_file, - dex_container_->GetMainSection()->Begin(), - /* update_input_vdex */ false)) { + const uint8_t* dex_src = nullptr; + if (dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &dex_container_, &error_msg)) { + oat_dex_file->dex_sections_layout_ = dex_layout.GetSections(); + // Dex layout can affect the size of the dex file, so we update here what we have set + // when adding the dex file as a source. + const UnalignedDexFileHeader* header = + AsUnalignedDexFileHeader(dex_container_->GetMainSection()->Begin()); + oat_dex_file->dex_file_size_ = header->file_size_; + dex_src = dex_container_->GetMainSection()->Begin(); + } else { + LOG(WARNING) << "Failed to run dex layout, reason:" << error_msg; + // Since we failed to convert the dex, just copy the input dex. + dex_src = dex_file->Begin(); + } + if (!WriteDexFile(out, oat_dex_file, dex_src, /* update_input_vdex */ false)) { return false; } if (dex_container_ != nullptr) { diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc index ca13f7588b..39cf86d4b2 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -16,6 +16,7 @@ #include "compact_dex_writer.h" +#include "android-base/stringprintf.h" #include "base/logging.h" #include "base/time_utils.h" #include "dex/compact_dex_debug_info.h" @@ -328,9 +329,63 @@ void CompactDexWriter::WriteStringData(Stream* stream, dex_ir::StringData* strin stream->Skip(1); } -void CompactDexWriter::Write(DexContainer* output) { +bool CompactDexWriter::CanGenerateCompactDex(std::string* error_msg) { + dex_ir::Collections& collections = header_->GetCollections(); + static constexpr InvokeType invoke_types[] = { + kDirect, + kVirtual + }; + std::vector<bool> saw_method_id(collections.MethodIdsSize(), false); + std::vector<dex_ir::CodeItem*> method_id_code_item(collections.MethodIdsSize(), nullptr); + std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(collections.MethodIdsSize(), nullptr); + for (InvokeType invoke_type : invoke_types) { + for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) { + // Skip classes that are not defined in this dex file. + dex_ir::ClassData* class_data = class_def->GetClassData(); + if (class_data == nullptr) { + continue; + } + for (auto& method : *(invoke_type == InvokeType::kDirect + ? class_data->DirectMethods() + : class_data->VirtualMethods())) { + const uint32_t idx = method->GetMethodId()->GetIndex(); + dex_ir::CodeItem* code_item = method->GetCodeItem(); + dex_ir:: DebugInfoItem* debug_info_item = nullptr; + if (code_item != nullptr) { + debug_info_item = code_item->DebugInfo(); + } + if (saw_method_id[idx]) { + if (method_id_code_item[idx] != code_item) { + *error_msg = android::base::StringPrintf("Conflicting code item for method id %u", + idx); + // Conflicting info, abort generation. + return false; + } + if (method_id_debug_info[idx] != debug_info_item) { + *error_msg = android::base::StringPrintf("Conflicting debug info for method id %u", + idx); + // Conflicting info, abort generation. + return false; + } + } + method_id_code_item[idx] = code_item; + method_id_debug_info[idx] = debug_info_item; + saw_method_id[idx] = true; + } + } + } + return true; +} + +bool CompactDexWriter::Write(DexContainer* output, std::string* error_msg) { + DCHECK(error_msg != nullptr); CHECK(compute_offsets_); CHECK(output->IsCompactDexContainer()); + + if (!CanGenerateCompactDex(error_msg)) { + return false; + } + Container* const container = down_cast<Container*>(output); // For now, use the same stream for both data and metadata. Stream temp_main_stream(output->GetMainSection()); @@ -472,6 +527,8 @@ void CompactDexWriter::Write(DexContainer* output) { // dex2oat's class unloading. The issue is that verification encounters quickened opcodes after // the first dex gets unloaded. code_item_dedupe_->Clear(); + + return true; } std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const { diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h index ea9f7d13db..0e7d65f9e4 100644 --- a/dexlayout/compact_dex_writer.h +++ b/dexlayout/compact_dex_writer.h @@ -136,7 +136,10 @@ class CompactDexWriter : public DexWriter { }; protected: - void Write(DexContainer* output) OVERRIDE; + // Return true if we can generate compact dex for the IR. + bool CanGenerateCompactDex(std::string* error_msg); + + bool Write(DexContainer* output, std::string* error_msg) OVERRIDE; std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE; diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index 808bfad029..eead13f69a 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -788,7 +788,9 @@ size_t DexWriter::GetHeaderSize() const { return sizeof(StandardDexFile::Header); } -void DexWriter::Write(DexContainer* output) { +bool DexWriter::Write(DexContainer* output, std::string* error_msg) { + DCHECK(error_msg != nullptr); + Stream stream_storage(output->GetMainSection()); Stream* stream = &stream_storage; @@ -905,11 +907,13 @@ void DexWriter::Write(DexContainer* output) { // Trim the map to make it sized as large as the dex file. output->GetMainSection()->Resize(header_->FileSize()); + return true; } -void DexWriter::Output(DexLayout* dex_layout, +bool DexWriter::Output(DexLayout* dex_layout, std::unique_ptr<DexContainer>* container, - bool compute_offsets) { + bool compute_offsets, + std::string* error_msg) { CHECK(dex_layout != nullptr); std::unique_ptr<DexWriter> writer; if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) { @@ -922,7 +926,7 @@ void DexWriter::Output(DexLayout* dex_layout, if (*container == nullptr) { *container = writer->CreateDexContainer(); } - writer->Write(container->get()); + return writer->Write(container->get(), error_msg); } void MapItemQueue::AddIfNotEmpty(const MapItem& item) { diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index 5df11116ee..df098c0f6f 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -214,14 +214,15 @@ class DexWriter { DexWriter(DexLayout* dex_layout, bool compute_offsets); - static void Output(DexLayout* dex_layout, + static bool Output(DexLayout* dex_layout, std::unique_ptr<DexContainer>* container, - bool compute_offsets); + bool compute_offsets, + std::string* error_msg) WARN_UNUSED; virtual ~DexWriter() {} protected: - virtual void Write(DexContainer* output); + virtual bool Write(DexContainer* output, std::string* error_msg); virtual std::unique_ptr<DexContainer> CreateDexContainer() const; void WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value); diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 91d35ff6d7..e841811861 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -1813,11 +1813,11 @@ void DexLayout::LayoutOutputFile(const DexFile* dex_file) { LayoutCodeItems(dex_file); } -void DexLayout::OutputDexFile(const DexFile* input_dex_file, +bool DexLayout::OutputDexFile(const DexFile* input_dex_file, bool compute_offsets, - std::unique_ptr<DexContainer>* dex_container) { + std::unique_ptr<DexContainer>* dex_container, + std::string* error_msg) { const std::string& dex_file_location = input_dex_file->GetLocation(); - std::string error_msg; std::unique_ptr<File> new_file; // If options_.output_dex_directory_ is non null, we are outputting to a file. if (options_.output_dex_directory_ != nullptr) { @@ -1834,35 +1834,39 @@ void DexLayout::OutputDexFile(const DexFile* input_dex_file, new_file.reset(OS::CreateEmptyFile(output_location.c_str())); if (new_file == nullptr) { LOG(ERROR) << "Could not create dex writer output file: " << output_location; - return; + return false; } } - DexWriter::Output(this, dex_container, compute_offsets); + if (!DexWriter::Output(this, dex_container, compute_offsets, error_msg)) { + return false; + } if (new_file != nullptr) { DexContainer* const container = dex_container->get(); DexContainer::Section* const main_section = container->GetMainSection(); if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) { LOG(ERROR) << "Failed to write main section for dex file " << dex_file_location; new_file->Erase(); - return; + return false; } DexContainer::Section* const data_section = container->GetDataSection(); if (!new_file->WriteFully(data_section->Begin(), data_section->Size())) { LOG(ERROR) << "Failed to write data section for dex file " << dex_file_location; new_file->Erase(); - return; + return false; } UNUSED(new_file->FlushCloseOrErase()); } + return true; } /* * Dumps the requested sections of the file. */ -void DexLayout::ProcessDexFile(const char* file_name, +bool DexLayout::ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index, - std::unique_ptr<DexContainer>* dex_container) { + std::unique_ptr<DexContainer>* dex_container, + std::string* error_msg) { const bool has_output_container = dex_container != nullptr; const bool output = options_.output_dex_directory_ != nullptr || has_output_container; @@ -1885,12 +1889,12 @@ void DexLayout::ProcessDexFile(const char* file_name, if (options_.visualize_pattern_) { VisualizeDexLayout(header_, dex_file, dex_file_index, info_); - return; + return true; } if (options_.show_section_statistics_) { ShowDexSectionStatistics(header_, dex_file_index); - return; + return true; } // Dump dex file. @@ -1912,7 +1916,9 @@ void DexLayout::ProcessDexFile(const char* file_name, dex_container = &temp_container; } // If we didn't set the offsets eagerly, we definitely need to compute them here. - OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container); + if (!OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container, error_msg)) { + return false; + } // Clear header before verifying to reduce peak RAM usage. const size_t file_size = header_->FileSize(); @@ -1920,7 +1926,6 @@ void DexLayout::ProcessDexFile(const char* file_name, // Verify the output dex file's structure, only enabled by default for debug builds. if (options_.verify_output_ && has_output_container) { - std::string error_msg; std::string location = "memory mapped file for " + std::string(file_name); // Dex file verifier cannot handle compact dex. bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone; @@ -1940,8 +1945,8 @@ void DexLayout::ProcessDexFile(const char* file_name, /*oat_dex_file*/ nullptr, verify, /*verify_checksum*/ false, - &error_msg)); - CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg; + error_msg)); + CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << *error_msg; // Do IR-level comparison between input and output. This check ignores potential differences // due to layout, so offsets are not checked. Instead, it checks the data contents of each @@ -1956,9 +1961,10 @@ void DexLayout::ProcessDexFile(const char* file_name, dex_ir::DexIrBuilder(*dex_file, /*eagerly_assign_offsets*/ true, GetOptions())); - CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg; + CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), error_msg)) << *error_msg; } } + return true; } /* @@ -1990,7 +1996,13 @@ int DexLayout::ProcessFile(const char* file_name) { } else { for (size_t i = 0; i < dex_files.size(); i++) { // Pass in a null container to avoid output by default. - ProcessDexFile(file_name, dex_files[i].get(), i, /*dex_container*/ nullptr); + if (!ProcessDexFile(file_name, + dex_files[i].get(), + i, + /*dex_container*/ nullptr, + &error_msg)) { + LOG(WARNING) << "Failed to run dex file " << i << " in " << file_name << " : " << error_msg; + } } } return 0; diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index 5635271dc1..b79a59209d 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -111,10 +111,11 @@ class DexLayout { header_(header) { } int ProcessFile(const char* file_name); - void ProcessDexFile(const char* file_name, + bool ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index, - std::unique_ptr<DexContainer>* dex_container); + std::unique_ptr<DexContainer>* dex_container, + std::string* error_msg); dex_ir::Header* GetHeader() const { return header_; } void SetHeader(dex_ir::Header* header) { header_ = header; } @@ -168,9 +169,10 @@ class DexLayout { // Creates a new layout for the dex file based on profile info. // Currently reorders ClassDefs, ClassDataItems, and CodeItems. void LayoutOutputFile(const DexFile* dex_file); - void OutputDexFile(const DexFile* input_dex_file, + bool OutputDexFile(const DexFile* input_dex_file, bool compute_offsets, - std::unique_ptr<DexContainer>* dex_container); + std::unique_ptr<DexContainer>* dex_container, + std::string* error_msg); void DumpCFG(const DexFile* dex_file, int idx); void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code); diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index a1901f08f3..d9a93ddf36 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -834,10 +834,13 @@ TEST_F(DexLayoutTest, ClassFilter) { /*out_file*/ nullptr, /*header*/ nullptr); std::unique_ptr<DexContainer> out; - dexlayout.ProcessDexFile(dex_file->GetLocation().c_str(), - dex_file.get(), - /*dex_file_index*/ 0, - &out); + bool result = dexlayout.ProcessDexFile( + dex_file->GetLocation().c_str(), + dex_file.get(), + /*dex_file_index*/ 0, + &out, + &error_msg); + ASSERT_TRUE(result) << "Failed to run dexlayout " << error_msg; std::unique_ptr<const DexFile> output_dex_file( dex_file_loader.OpenWithDataSection( out->GetMainSection()->Begin(), diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index e9522b3984..427d87eedf 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -104,10 +104,13 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi /*out_file*/ nullptr, /*header*/ nullptr); std::unique_ptr<art::DexContainer> dex_container; - dex_layout.ProcessDexFile(original.GetLocation().c_str(), - &original, - 0, - &dex_container); + bool result = dex_layout.ProcessDexFile( + original.GetLocation().c_str(), + &original, + 0, + &dex_container, + &error); + CHECK(result) << "Failed to generate dex file " << error; art::DexContainer::Section* main_section = dex_container->GetMainSection(); CHECK_EQ(dex_container->GetDataSection()->Size(), 0u); data.insert(data.end(), main_section->Begin(), main_section->End()); |