diff options
| -rw-r--r-- | dexlayout/dex_ir.cc | 45 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 63 |
2 files changed, 107 insertions, 1 deletions
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 2d9bbfdbb7..609068f41c 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -616,6 +616,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) { if (handler_off == existing_handlers->GetListOffset()) { handlers = existing_handlers.get(); + break; } } if (handlers == nullptr) { @@ -634,7 +635,51 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, TryItem* try_item = new TryItem(start_addr, insn_count, handlers); tries->push_back(std::unique_ptr<const TryItem>(try_item)); } + // Manually walk catch handlers list and add any missing handlers unreferenced by try items. + const uint8_t* handlers_base = DexFile::GetCatchHandlerData(disk_code_item, 0); + const uint8_t* handlers_data = handlers_base; + uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data); + while (handlers_size > handler_list->size()) { + bool already_added = false; + uint16_t handler_off = handlers_data - handlers_base; + for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) { + if (handler_off == existing_handlers->GetListOffset()) { + already_added = true; + break; + } + } + int32_t size = DecodeSignedLeb128(&handlers_data); + bool has_catch_all = size < 0; + if (has_catch_all) { + size = -size; + } + if (already_added == true) { + for (int32_t i = 0; i < size; i++) { + DecodeUnsignedLeb128(&handlers_data); + DecodeUnsignedLeb128(&handlers_data); + } + if (has_catch_all) { + DecodeUnsignedLeb128(&handlers_data); + } + continue; + } + TypeAddrPairVector* addr_pairs = new TypeAddrPairVector(); + for (int32_t i = 0; i < size; i++) { + const TypeId* type_id = GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data)); + uint32_t addr = DecodeUnsignedLeb128(&handlers_data); + addr_pairs->push_back( + std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr))); + } + if (has_catch_all) { + uint32_t addr = DecodeUnsignedLeb128(&handlers_data); + addr_pairs->push_back( + std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr))); + } + const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs); + handler_list->push_back(std::unique_ptr<const CatchHandler>(handler)); + } } + uint32_t size = GetCodeItemSize(dex_file, disk_code_item); CodeItem* code_item = new CodeItem( registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list); diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 562d948c5a..9881e283df 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -100,6 +100,26 @@ static const char kNullSetRefListElementInputDex[] = "ASAAAAIAAACEAQAABiAAAAIAAACwAQAAARAAAAIAAADYAQAAAiAAABIAAADoAQAAAyAAAAIAAADw" "AgAABCAAAAIAAAD8AgAAACAAAAIAAAAIAwAAABAAAAEAAAAgAwAA"; +// Dex file with catch handler unreferenced by try blocks. +// Constructed by building a dex file with try/catch blocks and hex editing. +static const char kUnreferencedCatchHandlerInputDex[] = + "ZGV4CjAzNQD+exd52Y0f9nY5x5GmInXq5nXrO6Kl2RV4AwAAcAAAAHhWNBIAAAAAAAAAANgCAAAS" + "AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAA0AgAARAEAANYB" + "AADeAQAA5gEAAO4BAAAAAgAADwIAACYCAAA9AgAAUQIAAGUCAAB5AgAAfwIAAIUCAACIAgAAjAIA" + "AKECAACnAgAArAIAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAwAAAAOAAAADAAAAAYAAAAAAAAA" + "DQAAAAYAAADIAQAADQAAAAYAAADQAQAABQABABAAAAAAAAAAAAAAAAAAAgAPAAAAAQABABEAAAAD" + "AAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAMgCAAAAAAAAAQABAAEAAAC1AgAABAAAAHAQ" + "AwAAAA4AAwABAAIAAgC6AgAAIQAAAGIAAAAaAQoAbiACABAAYgAAABoBCwBuIAIAEAAOAA0AYgAA" + "ABoBAQBuIAIAEAAo8A0AYgAAABoBAgBuIAIAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIBAg8BAhgA" + "AQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3QuamF2YQAN" + "TEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4Y2VwdGlv" + "bjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5" + "c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AARtYWluAANvdXQA" + "B3ByaW50bG4AAQAHDgAEAQAHDn17AncdHoseAAAAAgAAgYAExAIBCdwCAAANAAAAAAAAAAEAAAAA" + "AAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAAAAEAAAD8AAAABQAAAAQA" + "AAAEAQAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIAAADIAQAAAiAAABIAAADWAQAAAyAA" + "AAIAAAC1AgAAACAAAAEAAADIAgAAABAAAAEAAADYAgAA"; + static void WriteBase64ToFile(const char* base64, File* file) { // Decode base64. CHECK(base64 != nullptr); @@ -219,7 +239,7 @@ class DexLayoutTest : public CommonRuntimeTest { EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; std::vector<std::string> dexlayout_exec_argv = - { dexlayout, "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file }; + { dexlayout, "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file }; if (!::art::Exec(dexlayout_exec_argv, error_msg)) { return false; } @@ -236,6 +256,40 @@ class DexLayoutTest : public CommonRuntimeTest { } return true; } + + // Runs UnreferencedCatchHandlerTest. + bool UnreferencedCatchHandlerExec(std::string* error_msg) { + ScratchFile tmp_file; + 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); + + // Write inputs and expected outputs. + std::string input_dex = tmp_dir + "classes.dex"; + WriteFileBase64(kUnreferencedCatchHandlerInputDex, input_dex.c_str()); + std::string output_dex = tmp_dir + "classes.dex.new"; + + std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; + EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; + + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-w", tmp_dir, "-o", "/dev/null", input_dex }; + if (!::art::Exec(dexlayout_exec_argv, error_msg)) { + return false; + } + + // Diff input and output. They should be the same. + std::vector<std::string> diff_exec_argv = { "/usr/bin/diff", input_dex, output_dex }; + if (!::art::Exec(diff_exec_argv, error_msg)) { + return false; + } + + std::vector<std::string> rm_exec_argv = { "/bin/rm", input_dex, output_dex }; + if (!::art::Exec(rm_exec_argv, error_msg)) { + return false; + } + return true; + } }; @@ -297,4 +351,11 @@ TEST_F(DexLayoutTest, NullSetRefListElement) { } } +TEST_F(DexLayoutTest, UnreferencedCatchHandler) { + // Disable test on target. + TEST_DISABLED_FOR_TARGET(); + std::string error_msg; + ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg)) << error_msg; +} + } // namespace art |