Write link data for dexlayout
Instead of not writing out the link data and leaving an invalid
link_offset, write it out. Fixes dex verifier failures for a few
APKs.
Added test.
Test: test-art-host
Bug: 69561363
Change-Id: Iec1c331f74f9fd58658d4c13465a3bcb6295ce24
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 61a4eae..8421774 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -396,6 +396,14 @@
eagerly_assign_offsets_ = eagerly_assign_offsets;
}
+ void SetLinkData(std::vector<uint8_t>&& link_data) {
+ link_data_ = std::move(link_data);
+ }
+
+ const std::vector<uint8_t>& LinkData() const {
+ return link_data_;
+ }
+
private:
EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
EncodedValue* ReadEncodedValue(const DexFile& dex_file,
@@ -452,6 +460,9 @@
uint32_t map_list_offset_ = 0;
+ // Link data.
+ std::vector<uint8_t> link_data_;
+
// If we eagerly assign offsets during IR building or later after layout. Must be false if
// changing the layout is enabled.
bool eagerly_assign_offsets_;
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 924dfe0..1fd963f 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -80,6 +80,11 @@
// Sort the vectors by the map order (same order as the file).
collections.SortVectorsByMapOrder();
+ // Load the link data if it exists.
+ collections.SetLinkData(std::vector<uint8_t>(
+ dex_file.Begin() + dex_file.GetHeader().link_off_,
+ dex_file.Begin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_));
+
return header;
}
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index c85bca0..1fac235 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -878,7 +878,15 @@
}
}
- // TODO: Write link data?
+ // Write link data if it exists.
+ const std::vector<uint8_t>& link_data = collection.LinkData();
+ if (link_data.size() > 0) {
+ CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
+ if (compute_offsets_) {
+ header_->SetLinkOffset(offset);
+ }
+ offset += Write(&link_data[0], link_data.size(), header_->LinkOffset());
+ }
// Write header last.
if (compute_offsets_) {
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index c4f7acc..19c9038 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -732,4 +732,45 @@
dexlayout_args));
}
+// Test that link data is written out (or at least the header is updated).
+TEST_F(DexLayoutTest, LinkData) {
+ ScratchFile temp_dex;
+ size_t file_size = 0;
+ MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [&] (DexFile* dex) {
+ DexFile::Header& header = const_cast<DexFile::Header&>(dex->GetHeader());
+ header.link_off_ = header.file_size_;
+ header.link_size_ = 16 * KB;
+ header.file_size_ += header.link_size_;
+ file_size = header.file_size_;
+ });
+ TEMP_FAILURE_RETRY(temp_dex.GetFile()->SetLength(file_size));
+
+ std::string error_msg;
+
+ ScratchFile tmp_file;
+ const std::string& tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind('/');
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+ ScratchFile profile_file;
+
+ std::vector<std::string> dexlayout_args =
+ { "-i",
+ "-v",
+ "-w", tmp_dir,
+ "-o", tmp_name,
+ "-p", profile_file.GetFilename(),
+ temp_dex.GetFilename()
+ };
+ // -v makes sure that the layout did not corrupt the dex file.
+ ASSERT_TRUE(DexLayoutExec(&temp_dex,
+ /*dex_filename*/ nullptr,
+ &profile_file,
+ dexlayout_args));
+
+ std::string output_dex = temp_dex.GetFilename() + ".new";
+ std::vector<std::string> rm_exec_argv =
+ { "/bin/rm", output_dex };
+ ASSERT_TRUE(::art::Exec(rm_exec_argv, &error_msg));
+}
+
} // namespace art