diff options
author | huangs <huangs@chromium.org> | 2016-01-28 16:11:48 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-29 00:12:39 +0000 |
commit | 0a9cbf1781a114b35a4e0f4a834f2d24ade2e917 (patch) | |
tree | 964fa6b24b09ce95b4178692f0af9d28167ec331 /courgette | |
parent | b85b92b4639f690a9a523a910211d432dba568a2 (diff) | |
download | chromium_src-0a9cbf1781a114b35a4e0f4a834f2d24ade2e917.zip chromium_src-0a9cbf1781a114b35a4e0f4a834f2d24ade2e917.tar.gz chromium_src-0a9cbf1781a114b35a4e0f4a834f2d24ade2e917.tar.bz2 |
[Courgette] Refactor: Manage AssemblyProgram and EncodedProgram with scoped_ptr.
Previously naked pointers AssemblyProgram and EncodedProgram are used over the
place, and are deallocated using Delete{AssemblyProgram, EncodedProgram}().
In this CL we use scoped_ptr to manage the life cycles of these objects.
- Removed DeleteAssemblyProgram() and DeleteEncodedProgram() and replaced calls
with e.g., program.reset(nullptr); if the manual deallocation is a peak
memory optimization.
- Moved Encode() and ReadEncodedProgram() to the .h files matching the .cc files.
- Extracted DetectExecutableType() and ParseDetectedExecutable() from
disassembly.* to new files program_detector*c, since Disassembly is really an
implementation that caller's don't care about.
Review URL: https://codereview.chromium.org/1629703002
Cr-Commit-Position: refs/heads/master@{#372212}
Diffstat (limited to 'courgette')
-rw-r--r-- | courgette/BUILD.gn | 2 | ||||
-rw-r--r-- | courgette/adjustment_method_unittest.cc | 53 | ||||
-rw-r--r-- | courgette/assembly_program.cc | 50 | ||||
-rw-r--r-- | courgette/assembly_program.h | 11 | ||||
-rw-r--r-- | courgette/courgette.gyp | 2 | ||||
-rw-r--r-- | courgette/courgette.h | 36 | ||||
-rw-r--r-- | courgette/courgette_tool.cc | 79 | ||||
-rw-r--r-- | courgette/disassembler.cc | 93 | ||||
-rw-r--r-- | courgette/encode_decode_unittest.cc | 27 | ||||
-rw-r--r-- | courgette/encoded_program.cc | 24 | ||||
-rw-r--r-- | courgette/encoded_program.h | 7 | ||||
-rw-r--r-- | courgette/encoded_program_fuzz_unittest.cc | 28 | ||||
-rw-r--r-- | courgette/encoded_program_unittest.cc | 1 | ||||
-rw-r--r-- | courgette/ensemble.cc | 4 | ||||
-rw-r--r-- | courgette/patch_generator_x86_32.h | 50 | ||||
-rw-r--r-- | courgette/patcher_x86_32.h | 26 | ||||
-rw-r--r-- | courgette/program_detector.cc | 85 | ||||
-rw-r--r-- | courgette/program_detector.h | 43 |
18 files changed, 321 insertions, 300 deletions
diff --git a/courgette/BUILD.gn b/courgette/BUILD.gn index 6645093..8916c15 100644 --- a/courgette/BUILD.gn +++ b/courgette/BUILD.gn @@ -42,6 +42,8 @@ static_library("courgette_lib") { "memory_allocator.h", "patch_generator_x86_32.h", "patcher_x86_32.h", + "program_detector.cc", + "program_detector.h", "region.h", "rel32_finder_win32_x86.cc", "rel32_finder_win32_x86.h", diff --git a/courgette/adjustment_method_unittest.cc b/courgette/adjustment_method_unittest.cc index 5b213dc..e25a8e7 100644 --- a/courgette/adjustment_method_unittest.cc +++ b/courgette/adjustment_method_unittest.cc @@ -3,11 +3,13 @@ // found in the LICENSE file. #include <string> +#include <utility> +#include "base/memory/scoped_ptr.h" #include "base/strings/string_util.h" - #include "courgette/assembly_program.h" #include "courgette/courgette.h" +#include "courgette/encoded_program.h" #include "courgette/streams.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,11 +25,11 @@ class AdjustmentMethodTest : public testing::Test { void TearDown() { } - // Returns one of two similar a simple programs. They differ only in the - // label assignment, so that it is possible to make them look identical. - courgette::AssemblyProgram* MakeProgram(int kind) const { - courgette::AssemblyProgram* prog = - new courgette::AssemblyProgram(courgette::EXE_WIN_32_X86); + // Returns one of two similar simple programs. These differ only in Label + // assignment, so it is possible to make them look identical. + scoped_ptr<courgette::AssemblyProgram> MakeProgram(int kind) const { + scoped_ptr<courgette::AssemblyProgram> prog( + new courgette::AssemblyProgram(courgette::EXE_WIN_32_X86)); prog->set_image_base(0x00400000); courgette::Label* labelA = prog->FindOrMakeAbs32Label(0x00410000); @@ -52,24 +54,29 @@ class AdjustmentMethodTest : public testing::Test { return prog; } - courgette::AssemblyProgram* MakeProgramA() const { return MakeProgram(0); } - courgette::AssemblyProgram* MakeProgramB() const { return MakeProgram(1); } + scoped_ptr<courgette::AssemblyProgram> MakeProgramA() const { + return MakeProgram(0); + } + scoped_ptr<courgette::AssemblyProgram> MakeProgramB() const { + return MakeProgram(1); + } // Returns a string that is the serialized version of |program|. // Deletes |program|. - std::string Serialize(courgette::AssemblyProgram *program) const { - courgette::EncodedProgram* encoded = NULL; + std::string Serialize(scoped_ptr<courgette::AssemblyProgram> program) const { + scoped_ptr<courgette::EncodedProgram> encoded; - const courgette::Status encode_status = Encode(program, &encoded); + const courgette::Status encode_status = Encode(*program, &encoded); EXPECT_EQ(courgette::C_OK, encode_status); - DeleteAssemblyProgram(program); + program.reset(); courgette::SinkStreamSet sinks; - const courgette::Status write_status = WriteEncodedProgram(encoded, &sinks); + const courgette::Status write_status = + WriteEncodedProgram(encoded.get(), &sinks); EXPECT_EQ(courgette::C_OK, write_status); - DeleteEncodedProgram(encoded); + encoded.reset(); courgette::SinkStream sink; bool can_collect = sinks.CopyTo(&sink); @@ -82,20 +89,20 @@ class AdjustmentMethodTest : public testing::Test { void AdjustmentMethodTest::Test1() const { - courgette::AssemblyProgram* prog1 = MakeProgramA(); - courgette::AssemblyProgram* prog2 = MakeProgramB(); - std::string s1 = Serialize(prog1); - std::string s2 = Serialize(prog2); + scoped_ptr<courgette::AssemblyProgram> prog1 = MakeProgramA(); + scoped_ptr<courgette::AssemblyProgram> prog2 = MakeProgramB(); + std::string s1 = Serialize(std::move(prog1)); + std::string s2 = Serialize(std::move(prog2)); // Don't use EXPECT_EQ because strings are unprintable. EXPECT_FALSE(s1 == s2); // Unadjusted A and B differ. - courgette::AssemblyProgram* prog5 = MakeProgramA(); - courgette::AssemblyProgram* prog6 = MakeProgramB(); - courgette::Status can_adjust = Adjust(*prog5, prog6); + scoped_ptr<courgette::AssemblyProgram> prog5 = MakeProgramA(); + scoped_ptr<courgette::AssemblyProgram> prog6 = MakeProgramB(); + courgette::Status can_adjust = Adjust(*prog5, prog6.get()); EXPECT_EQ(courgette::C_OK, can_adjust); - std::string s5 = Serialize(prog5); - std::string s6 = Serialize(prog6); + std::string s5 = Serialize(std::move(prog5)); + std::string s6 = Serialize(std::move(prog6)); EXPECT_TRUE(s1 == s5); // Adjustment did not change A (prog5) EXPECT_TRUE(s5 == s6); // Adjustment did change B into A diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc index 20eee96..de843f1 100644 --- a/courgette/assembly_program.cc +++ b/courgette/assembly_program.cc @@ -7,16 +7,12 @@ #include <memory.h> #include <stddef.h> #include <stdint.h> -#include <algorithm> -#include <map> -#include <set> -#include <sstream> + +#include <utility> #include <vector> #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" - #include "courgette/courgette.h" #include "courgette/encoded_program.h" @@ -365,13 +361,13 @@ void AssemblyProgram::AssignRemainingIndexes(RVAToLabel* labels) { << " infill " << fill_infill_count; } -EncodedProgram* AssemblyProgram::Encode() const { +scoped_ptr<EncodedProgram> AssemblyProgram::Encode() const { scoped_ptr<EncodedProgram> encoded(new EncodedProgram()); encoded->set_image_base(image_base_); if (!encoded->DefineLabels(abs32_labels_, rel32_labels_)) - return NULL; + return nullptr; for (size_t i = 0; i < instructions_.size(); ++i) { Instruction* instruction = instructions_[i]; @@ -380,13 +376,13 @@ EncodedProgram* AssemblyProgram::Encode() const { case ORIGIN: { OriginInstruction* org = static_cast<OriginInstruction*>(instruction); if (!encoded->AddOrigin(org->origin_rva())) - return NULL; + return nullptr; break; } case DEFBYTE: { uint8_t b = static_cast<ByteInstruction*>(instruction)->byte_value(); if (!encoded->AddCopy(1, &b)) - return NULL; + return nullptr; break; } case DEFBYTES: { @@ -395,13 +391,13 @@ EncodedProgram* AssemblyProgram::Encode() const { size_t len = static_cast<BytesInstruction*>(instruction)->len(); if (!encoded->AddCopy(len, byte_values)) - return NULL; + return nullptr; break; } case REL32: { Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); if (!encoded->AddRel32(label->index_)) - return NULL; + return nullptr; break; } case REL32ARM: { @@ -410,34 +406,34 @@ EncodedProgram* AssemblyProgram::Encode() const { uint16_t compressed_op = static_cast<InstructionWithLabelARM*>(instruction)->compressed_op(); if (!encoded->AddRel32ARM(compressed_op, label->index_)) - return NULL; + return nullptr; break; } case ABS32: { Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); if (!encoded->AddAbs32(label->index_)) - return NULL; + return nullptr; break; } case ABS64: { Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); if (!encoded->AddAbs64(label->index_)) - return NULL; + return nullptr; break; } case MAKEPERELOCS: { if (!encoded->AddPeMakeRelocs(kind_)) - return NULL; + return nullptr; break; } case MAKEELFRELOCS: { if (!encoded->AddElfMakeRelocs()) - return NULL; + return nullptr; break; } case MAKEELFARMRELOCS: { if (!encoded->AddElfARMMakeRelocs()) - return NULL; + return nullptr; break; } default: { @@ -446,7 +442,7 @@ EncodedProgram* AssemblyProgram::Encode() const { } } - return encoded.release(); + return encoded; } Instruction* AssemblyProgram::GetByteInstruction(uint8_t byte) { @@ -530,15 +526,13 @@ CheckBool AssemblyProgram::TrimLabels() { //////////////////////////////////////////////////////////////////////////////// -Status Encode(AssemblyProgram* program, EncodedProgram** output) { - *output = NULL; - EncodedProgram *encoded = program->Encode(); - if (encoded) { - *output = encoded; - return C_OK; - } else { - return C_GENERAL_ERROR; - } +Status Encode(const AssemblyProgram& program, + scoped_ptr<EncodedProgram>* output) { + // Explicitly release any memory associated with the output before encoding. + output->reset(); + + *output = program.Encode(); + return (*output) ? C_OK : C_GENERAL_ERROR; } } // namespace courgette diff --git a/courgette/assembly_program.h b/courgette/assembly_program.h index 45658ab..c256f8f 100644 --- a/courgette/assembly_program.h +++ b/courgette/assembly_program.h @@ -14,7 +14,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "courgette/disassembler.h" +#include "courgette/courgette.h" #include "courgette/image_utils.h" #include "courgette/label_manager.h" #include "courgette/memory_allocator.h" @@ -132,7 +132,7 @@ class AssemblyProgram { void UnassignIndexes(); void AssignRemainingIndexes(); - EncodedProgram* Encode() const; + scoped_ptr<EncodedProgram> Encode() const; // Accessor for instruction list. const InstructionVector& instructions() const { @@ -191,5 +191,12 @@ class AssemblyProgram { DISALLOW_COPY_AND_ASSIGN(AssemblyProgram); }; +// Converts |program| into encoded form, returning it as |*output|. +// Returns C_OK if succeeded, otherwise returns an error status and sets +// |*output| to null. +Status Encode(const AssemblyProgram& program, + scoped_ptr<EncodedProgram>* output); + } // namespace courgette + #endif // COURGETTE_ASSEMBLY_PROGRAM_H_ diff --git a/courgette/courgette.gyp b/courgette/courgette.gyp index 3983f19..f5e4031 100644 --- a/courgette/courgette.gyp +++ b/courgette/courgette.gyp @@ -40,6 +40,8 @@ 'label_manager.h', 'memory_allocator.cc', 'memory_allocator.h', + 'program_detector.cc', + 'program_detector.h', 'region.h', 'rel32_finder_win32_x86.cc', 'rel32_finder_win32_x86.h', diff --git a/courgette/courgette.h b/courgette/courgette.h index 5a98a46..84ab7cd 100644 --- a/courgette/courgette.h +++ b/courgette/courgette.h @@ -90,30 +90,6 @@ Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name, Status GenerateEnsemblePatch(SourceStream* old, SourceStream* target, SinkStream* patch); -// Detects the type of an executable file, and it's length. The length -// may be slightly smaller than some executables (like ELF), but will include -// all bytes the courgette algorithm has special benefit for. -// On success: -// Fill in type and detected_length, and return C_OK. -// On failure: -// Fill in type with UNKNOWN, detected_length with 0, and -// return C_INPUT_NOT_RECOGNIZED -Status DetectExecutableType(const void* buffer, size_t length, - ExecutableType* type, - size_t* detected_length); - -// Attempts to detect the type of executable, and parse it with the -// appropriate tools, storing the pointer to the AssemblyProgram in |*output|. -// Returns C_OK if successful, otherwise returns an error status and sets -// |*output| to NULL. -Status ParseDetectedExecutable(const void* buffer, size_t length, - AssemblyProgram** output); - -// Converts |program| into encoded form, returning it as |*output|. -// Returns C_OK if succeeded, otherwise returns an error status and -// sets |*output| to NULL -Status Encode(AssemblyProgram* program, EncodedProgram** output); - // Serializes |encoded| into the stream set. // Returns C_OK if succeeded, otherwise returns an error status. Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink); @@ -123,20 +99,10 @@ Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink); // |buffer| in an undefined state. Status Assemble(EncodedProgram* encoded, SinkStream* buffer); -// Deserializes program from the stream set. -// Returns C_OK if succeeded, otherwise returns an error status and -// sets |*output| to NULL -Status ReadEncodedProgram(SourceStreamSet* source, EncodedProgram** output); - -// Used to free an AssemblyProgram returned by other APIs. -void DeleteAssemblyProgram(AssemblyProgram* program); - -// Used to free an EncodedProgram returned by other APIs. -void DeleteEncodedProgram(EncodedProgram* encoded); - // Adjusts |program| to look more like |model|. // Status Adjust(const AssemblyProgram& model, AssemblyProgram *program); } // namespace courgette + #endif // COURGETTE_COURGETTE_H_ diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc index c7e7196..3e85657 100644 --- a/courgette/courgette_tool.cc +++ b/courgette/courgette_tool.cc @@ -13,10 +13,14 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "courgette/assembly_program.h" #include "courgette/courgette.h" +#include "courgette/encoded_program.h" +#include "courgette/program_detector.h" #include "courgette/streams.h" #include "courgette/third_party/bsdiff.h" @@ -76,30 +80,27 @@ void Disassemble(const base::FilePath& input_file, const base::FilePath& output_file) { std::string buffer = ReadOrFail(input_file, "input"); - courgette::AssemblyProgram* program = NULL; + scoped_ptr<courgette::AssemblyProgram> program; const courgette::Status parse_status = courgette::ParseDetectedExecutable(buffer.c_str(), buffer.length(), &program); - if (parse_status != courgette::C_OK) Problem("Can't parse input (code = %d).", parse_status); - courgette::EncodedProgram* encoded = NULL; - const courgette::Status encode_status = Encode(program, &encoded); - - courgette::DeleteAssemblyProgram(program); - + scoped_ptr<courgette::EncodedProgram> encoded; + const courgette::Status encode_status = Encode(*program, &encoded); if (encode_status != courgette::C_OK) Problem("Can't encode program."); - courgette::SinkStreamSet sinks; + program.reset(); + courgette::SinkStreamSet sinks; const courgette::Status write_status = - courgette::WriteEncodedProgram(encoded, &sinks); + courgette::WriteEncodedProgram(encoded.get(), &sinks); if (write_status != courgette::C_OK) Problem("Can't serialize encoded program."); - courgette::DeleteEncodedProgram(encoded); + encoded.reset(); courgette::SinkStream sink; if (!sinks.CopyTo(&sink)) @@ -159,7 +160,7 @@ void DisassembleAndAdjust(const base::FilePath& program_file, std::string program_buffer = ReadOrFail(program_file, "program"); std::string model_buffer = ReadOrFail(model_file, "reference"); - courgette::AssemblyProgram* program = NULL; + scoped_ptr<courgette::AssemblyProgram> program; const courgette::Status parse_program_status = courgette::ParseDetectedExecutable(program_buffer.c_str(), program_buffer.length(), @@ -167,7 +168,7 @@ void DisassembleAndAdjust(const base::FilePath& program_file, if (parse_program_status != courgette::C_OK) Problem("Can't parse program input (code = %d).", parse_program_status); - courgette::AssemblyProgram* model = NULL; + scoped_ptr<courgette::AssemblyProgram> model; const courgette::Status parse_model_status = courgette::ParseDetectedExecutable(model_buffer.c_str(), model_buffer.length(), @@ -175,26 +176,26 @@ void DisassembleAndAdjust(const base::FilePath& program_file, if (parse_model_status != courgette::C_OK) Problem("Can't parse model input (code = %d).", parse_model_status); - const courgette::Status adjust_status = Adjust(*model, program); + const courgette::Status adjust_status = Adjust(*model, program.get()); if (adjust_status != courgette::C_OK) Problem("Can't adjust program."); - courgette::EncodedProgram* encoded = NULL; - const courgette::Status encode_status = Encode(program, &encoded); - - courgette::DeleteAssemblyProgram(program); + model.reset(); + scoped_ptr<courgette::EncodedProgram> encoded; + const courgette::Status encode_status = Encode(*program, &encoded); if (encode_status != courgette::C_OK) Problem("Can't encode program."); - courgette::SinkStreamSet sinks; + program.reset(); + courgette::SinkStreamSet sinks; const courgette::Status write_status = - courgette::WriteEncodedProgram(encoded, &sinks); + courgette::WriteEncodedProgram(encoded.get(), &sinks); if (write_status != courgette::C_OK) Problem("Can't serialize encoded program."); - courgette::DeleteEncodedProgram(encoded); + encoded.reset(); courgette::SinkStream sink; if (!sinks.CopyTo(&sink)) @@ -215,7 +216,7 @@ void DisassembleAdjustDiff(const base::FilePath& model_file, std::string model_buffer = ReadOrFail(model_file, "'old'"); std::string program_buffer = ReadOrFail(program_file, "'new'"); - courgette::AssemblyProgram* model = NULL; + scoped_ptr<courgette::AssemblyProgram> model; const courgette::Status parse_model_status = courgette::ParseDetectedExecutable(model_buffer.c_str(), model_buffer.length(), @@ -223,7 +224,7 @@ void DisassembleAdjustDiff(const base::FilePath& model_file, if (parse_model_status != courgette::C_OK) Problem("Can't parse model input (code = %d).", parse_model_status); - courgette::AssemblyProgram* program = NULL; + scoped_ptr<courgette::AssemblyProgram> program; const courgette::Status parse_program_status = courgette::ParseDetectedExecutable(program_buffer.c_str(), program_buffer.length(), @@ -232,37 +233,41 @@ void DisassembleAdjustDiff(const base::FilePath& model_file, Problem("Can't parse program input (code = %d).", parse_program_status); if (adjust) { - const courgette::Status adjust_status = Adjust(*model, program); + const courgette::Status adjust_status = Adjust(*model, program.get()); if (adjust_status != courgette::C_OK) Problem("Can't adjust program."); } - courgette::EncodedProgram* encoded_program = NULL; + scoped_ptr<courgette::EncodedProgram> encoded_program; const courgette::Status encode_program_status = - Encode(program, &encoded_program); - courgette::DeleteAssemblyProgram(program); + Encode(*program, &encoded_program); if (encode_program_status != courgette::C_OK) Problem("Can't encode program."); - courgette::EncodedProgram* encoded_model = NULL; - const courgette::Status encode_model_status = Encode(model, &encoded_model); - courgette::DeleteAssemblyProgram(model); + program.reset(); + + scoped_ptr<courgette::EncodedProgram> encoded_model; + const courgette::Status encode_model_status = Encode(*model, &encoded_model); if (encode_model_status != courgette::C_OK) Problem("Can't encode model."); + model.reset(); + courgette::SinkStreamSet program_sinks; const courgette::Status write_program_status = - courgette::WriteEncodedProgram(encoded_program, &program_sinks); + courgette::WriteEncodedProgram(encoded_program.get(), &program_sinks); if (write_program_status != courgette::C_OK) Problem("Can't serialize encoded program."); - courgette::DeleteEncodedProgram(encoded_program); + + encoded_program.reset(); courgette::SinkStreamSet model_sinks; const courgette::Status write_model_status = - courgette::WriteEncodedProgram(encoded_model, &model_sinks); + courgette::WriteEncodedProgram(encoded_model.get(), &model_sinks); if (write_model_status != courgette::C_OK) Problem("Can't serialize encoded model."); - courgette::DeleteEncodedProgram(encoded_model); + + encoded_model.reset(); courgette::SinkStream empty_sink; for (int i = 0; ; ++i) { @@ -295,14 +300,16 @@ void Assemble(const base::FilePath& input_file, if (!sources.Init(buffer.c_str(), buffer.length())) Problem("Bad input file."); - courgette::EncodedProgram* encoded = NULL; - const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded); + scoped_ptr<courgette::EncodedProgram> encoded; + const courgette::Status read_status = + courgette::ReadEncodedProgram(&sources, &encoded); if (read_status != courgette::C_OK) Problem("Bad encoded program."); courgette::SinkStream sink; - const courgette::Status assemble_status = courgette::Assemble(encoded, &sink); + const courgette::Status assemble_status = + courgette::Assemble(encoded.get(), &sink); if (assemble_status != courgette::C_OK) Problem("Can't assemble."); diff --git a/courgette/disassembler.cc b/courgette/disassembler.cc index 568114c..b9fce8b 100644 --- a/courgette/disassembler.cc +++ b/courgette/disassembler.cc @@ -4,101 +4,8 @@ #include "courgette/disassembler.h" -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <string> -#include <vector> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "courgette/assembly_program.h" -#include "courgette/courgette.h" -#include "courgette/disassembler_elf_32_arm.h" -#include "courgette/disassembler_elf_32_x86.h" -#include "courgette/disassembler_win32_x64.h" -#include "courgette/disassembler_win32_x86.h" -#include "courgette/encoded_program.h" - namespace courgette { -//////////////////////////////////////////////////////////////////////////////// - -Disassembler* DetectDisassembler(const void* buffer, size_t length) { - Disassembler* disassembler = NULL; - - disassembler = new DisassemblerWin32X86(buffer, length); - if (disassembler->ParseHeader()) - return disassembler; - else - delete disassembler; - - disassembler = new DisassemblerWin32X64(buffer, length); - if (disassembler->ParseHeader()) - return disassembler; - else - delete disassembler; - - disassembler = new DisassemblerElf32X86(buffer, length); - if (disassembler->ParseHeader()) - return disassembler; - else - delete disassembler; - - disassembler = new DisassemblerElf32ARM(buffer, length); - if (disassembler->ParseHeader()) - return disassembler; - else - delete disassembler; - - return NULL; -} - -Status DetectExecutableType(const void* buffer, size_t length, - ExecutableType* type, - size_t* detected_length) { - - Disassembler* disassembler = DetectDisassembler(buffer, length); - - if (disassembler) { - *type = disassembler->kind(); - *detected_length = disassembler->length(); - delete disassembler; - return C_OK; - } - - // We failed to detect anything - *type = EXE_UNKNOWN; - *detected_length = 0; - return C_INPUT_NOT_RECOGNIZED; -} - -Status ParseDetectedExecutable(const void* buffer, size_t length, - AssemblyProgram** output) { - *output = nullptr; - - scoped_ptr<Disassembler> disassembler(DetectDisassembler(buffer, length)); - if (!disassembler) - return C_INPUT_NOT_RECOGNIZED; - - scoped_ptr<AssemblyProgram> program( - new AssemblyProgram(disassembler->kind())); - - if (!disassembler->Disassemble(program.get())) - return C_DISASSEMBLY_FAILED; - - if (!program->TrimLabels()) - return C_TRIM_FAILED; - - *output = program.release(); - return C_OK; -} - -void DeleteAssemblyProgram(AssemblyProgram* program) { - delete program; -} - Disassembler::Disassembler(const void* start, size_t length) : failure_reason_("uninitialized") { start_ = reinterpret_cast<const uint8_t*>(start); diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc index 9e89c20..7494785 100644 --- a/courgette/encode_decode_unittest.cc +++ b/courgette/encode_decode_unittest.cc @@ -4,8 +4,12 @@ #include <stddef.h> +#include "base/memory/scoped_ptr.h" +#include "courgette/assembly_program.h" #include "courgette/base_test_unittest.h" #include "courgette/courgette.h" +#include "courgette/encoded_program.h" +#include "courgette/program_detector.h" #include "courgette/streams.h" class EncodeDecodeTest : public BaseTest { @@ -20,25 +24,25 @@ void EncodeDecodeTest::TestAssembleToStreamDisassemble( const void* original_buffer = file.c_str(); size_t original_length = file.length(); - courgette::AssemblyProgram* program = NULL; + scoped_ptr<courgette::AssemblyProgram> program; const courgette::Status parse_status = courgette::ParseDetectedExecutable(original_buffer, original_length, &program); EXPECT_EQ(courgette::C_OK, parse_status); - courgette::EncodedProgram* encoded = NULL; - - const courgette::Status encode_status = Encode(program, &encoded); + scoped_ptr<courgette::EncodedProgram> encoded; + const courgette::Status encode_status = Encode(*program, &encoded); EXPECT_EQ(courgette::C_OK, encode_status); - DeleteAssemblyProgram(program); + program.reset(); courgette::SinkStreamSet sinks; - const courgette::Status write_status = WriteEncodedProgram(encoded, &sinks); + const courgette::Status write_status = + WriteEncodedProgram(encoded.get(), &sinks); EXPECT_EQ(courgette::C_OK, write_status); - DeleteEncodedProgram(encoded); + encoded.reset(); courgette::SinkStream sink; bool can_collect = sinks.CopyTo(&sink); @@ -53,21 +57,22 @@ void EncodeDecodeTest::TestAssembleToStreamDisassemble( bool can_get_source_streams = sources.Init(buffer, length); EXPECT_TRUE(can_get_source_streams); - courgette::EncodedProgram *encoded2 = NULL; + scoped_ptr<courgette::EncodedProgram> encoded2; const courgette::Status read_status = ReadEncodedProgram(&sources, &encoded2); EXPECT_EQ(courgette::C_OK, read_status); courgette::SinkStream assembled; - const courgette::Status assemble_status = Assemble(encoded2, &assembled); + const courgette::Status assemble_status = + Assemble(encoded2.get(), &assembled); EXPECT_EQ(courgette::C_OK, assemble_status); + encoded2.reset(); + const void* assembled_buffer = assembled.Buffer(); size_t assembled_length = assembled.Length(); EXPECT_EQ(original_length, assembled_length); EXPECT_EQ(0, memcmp(original_buffer, assembled_buffer, original_length)); - - DeleteEncodedProgram(encoded2); } TEST_F(EncodeDecodeTest, PE) { diff --git a/courgette/encoded_program.cc b/courgette/encoded_program.cc index 59800c5..76fb33e 100644 --- a/courgette/encoded_program.cc +++ b/courgette/encoded_program.cc @@ -10,11 +10,11 @@ #include <algorithm> #include <map> #include <string> +#include <utility> #include <vector> #include "base/environment.h" #include "base/logging.h" -#include "base/memory/scoped_ptr.h" #include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" #include "base/strings/string_number_conversions.h" @@ -22,7 +22,6 @@ #include "courgette/courgette.h" #include "courgette/disassembler_elf_32_arm.h" #include "courgette/streams.h" -#include "courgette/types_elf.h" namespace courgette { @@ -781,14 +780,15 @@ Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink) { return C_OK; } -Status ReadEncodedProgram(SourceStreamSet* streams, EncodedProgram** output) { - EncodedProgram* encoded = new EncodedProgram(); - if (encoded->ReadFrom(streams)) { - *output = encoded; - return C_OK; - } - delete encoded; - return C_DESERIALIZATION_FAILED; +Status ReadEncodedProgram(SourceStreamSet* streams, + scoped_ptr<EncodedProgram>* output) { + output->reset(); + scoped_ptr<EncodedProgram> encoded(new EncodedProgram()); + if (!encoded->ReadFrom(streams)) + return C_DESERIALIZATION_FAILED; + + *output = std::move(encoded); + return C_OK; } Status Assemble(EncodedProgram* encoded, SinkStream* buffer) { @@ -798,8 +798,4 @@ Status Assemble(EncodedProgram* encoded, SinkStream* buffer) { return C_ASSEMBLY_FAILED; } -void DeleteEncodedProgram(EncodedProgram* encoded) { - delete encoded; -} - } // namespace courgette diff --git a/courgette/encoded_program.h b/courgette/encoded_program.h index e89676d..6ea3e22 100644 --- a/courgette/encoded_program.h +++ b/courgette/encoded_program.h @@ -11,6 +11,7 @@ #include <vector> #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "courgette/disassembler.h" #include "courgette/label_manager.h" #include "courgette/memory_allocator.h" @@ -140,5 +141,11 @@ class EncodedProgram { DISALLOW_COPY_AND_ASSIGN(EncodedProgram); }; +// Deserializes program from a stream set to |*output|. Returns C_OK if +// successful, otherwise assigns |*output| to null and returns an error status. +Status ReadEncodedProgram(SourceStreamSet* source, + scoped_ptr<EncodedProgram>* output); + } // namespace courgette + #endif // COURGETTE_ENCODED_PROGRAM_H_ diff --git a/courgette/encoded_program_fuzz_unittest.cc b/courgette/encoded_program_fuzz_unittest.cc index b755f85..ed301f1 100644 --- a/courgette/encoded_program_fuzz_unittest.cc +++ b/courgette/encoded_program_fuzz_unittest.cc @@ -10,13 +10,16 @@ // // We try a lot of arbitrary modifications to the serialized form and make sure // that the outcome is not a crash. - -#include "base/test/test_suite.h" +#include "courgette/encoded_program.h" #include <stddef.h> +#include "base/memory/scoped_ptr.h" +#include "base/test/test_suite.h" +#include "courgette/assembly_program.h" #include "courgette/base_test_unittest.h" #include "courgette/courgette.h" +#include "courgette/program_detector.h" #include "courgette/streams.h" class DecodeFuzzTest : public BaseTest { @@ -40,24 +43,24 @@ void DecodeFuzzTest::FuzzExe(const char* file_name) const { const void* original_buffer = file1.c_str(); size_t original_length = file1.length(); - courgette::AssemblyProgram* program = NULL; + scoped_ptr<courgette::AssemblyProgram> program; const courgette::Status parse_status = courgette::ParseDetectedExecutable(original_buffer, original_length, &program); EXPECT_EQ(courgette::C_OK, parse_status); - courgette::EncodedProgram* encoded = NULL; - - const courgette::Status encode_status = Encode(program, &encoded); + scoped_ptr<courgette::EncodedProgram> encoded; + const courgette::Status encode_status = Encode(*program, &encoded); EXPECT_EQ(courgette::C_OK, encode_status); - DeleteAssemblyProgram(program); + program.reset(); courgette::SinkStreamSet sinks; - const courgette::Status write_status = WriteEncodedProgram(encoded, &sinks); + const courgette::Status write_status = + WriteEncodedProgram(encoded.get(), &sinks); EXPECT_EQ(courgette::C_OK, write_status); - DeleteEncodedProgram(encoded); + encoded.reset(); courgette::SinkStream sink; bool can_collect = sinks.CopyTo(&sink); @@ -170,7 +173,7 @@ void DecodeFuzzTest::FuzzBits(const std::string& base_buffer, bool DecodeFuzzTest::TryAssemble(const std::string& buffer, std::string* output) const { - courgette::EncodedProgram *encoded = NULL; + scoped_ptr<courgette::EncodedProgram> encoded; bool result = false; courgette::SourceStreamSet sources; @@ -180,7 +183,8 @@ bool DecodeFuzzTest::TryAssemble(const std::string& buffer, ReadEncodedProgram(&sources, &encoded); if (read_status == courgette::C_OK) { courgette::SinkStream assembled; - const courgette::Status assemble_status = Assemble(encoded, &assembled); + const courgette::Status assemble_status = + Assemble(encoded.get(), &assembled); if (assemble_status == courgette::C_OK) { const void* assembled_buffer = assembled.Buffer(); @@ -194,8 +198,6 @@ bool DecodeFuzzTest::TryAssemble(const std::string& buffer, } } - DeleteEncodedProgram(encoded); - return result; } diff --git a/courgette/encoded_program_unittest.cc b/courgette/encoded_program_unittest.cc index 654ef44..41ed7ee 100644 --- a/courgette/encoded_program_unittest.cc +++ b/courgette/encoded_program_unittest.cc @@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "courgette/disassembler.h" #include "courgette/image_utils.h" #include "courgette/label_manager.h" #include "courgette/streams.h" diff --git a/courgette/ensemble.cc b/courgette/ensemble.cc index d5277a4..631dd12 100644 --- a/courgette/ensemble.cc +++ b/courgette/ensemble.cc @@ -8,7 +8,7 @@ #include <stdint.h> #include "base/strings/string_number_conversions.h" - +#include "courgette/program_detector.h" #include "courgette/region.h" #include "courgette/simple_delta.h" #include "courgette/streams.h" @@ -41,11 +41,9 @@ Status Ensemble::FindEmbeddedElements() { while (position < length) { ExecutableType type; size_t detected_length; - Status result = DetectExecutableType(start + position, length - position, &type, &detected_length); - if (result == C_OK) { Region region(start + position, detected_length); diff --git a/courgette/patch_generator_x86_32.h b/courgette/patch_generator_x86_32.h index 1c56712..40a20f2 100644 --- a/courgette/patch_generator_x86_32.h +++ b/courgette/patch_generator_x86_32.h @@ -13,6 +13,7 @@ #include "base/memory/scoped_ptr.h" #include "courgette/assembly_program.h" #include "courgette/ensemble.h" +#include "courgette/program_detector.h" namespace courgette { @@ -61,7 +62,7 @@ class PatchGeneratorX86_32 : public TransformationPatchGenerator { // Generate old version of program using |corrected_parameters|. // TODO(sra): refactor to use same code from patcher_. - AssemblyProgram* old_program = NULL; + scoped_ptr<AssemblyProgram> old_program; Status old_parse_status = ParseDetectedExecutable(old_element_->region().start(), old_element_->region().length(), @@ -71,52 +72,46 @@ class PatchGeneratorX86_32 : public TransformationPatchGenerator { return old_parse_status; } - AssemblyProgram* new_program = NULL; + // TODO(huangs): Move the block below to right before |new_program| gets + // used, so we can reduce Courgette-gen peak memory. + scoped_ptr<AssemblyProgram> new_program; Status new_parse_status = ParseDetectedExecutable(new_element_->region().start(), new_element_->region().length(), &new_program); if (new_parse_status != C_OK) { - DeleteAssemblyProgram(old_program); LOG(ERROR) << "Cannot parse an executable " << new_element_->Name(); return new_parse_status; } - EncodedProgram* old_encoded = NULL; - Status old_encode_status = Encode(old_program, &old_encoded); - if (old_encode_status != C_OK) { - DeleteAssemblyProgram(old_program); + scoped_ptr<EncodedProgram> old_encoded; + Status old_encode_status = Encode(*old_program, &old_encoded); + if (old_encode_status != C_OK) return old_encode_status; - } Status old_write_status = - WriteEncodedProgram(old_encoded, old_transformed_element); - DeleteEncodedProgram(old_encoded); - if (old_write_status != C_OK) { - DeleteAssemblyProgram(old_program); + WriteEncodedProgram(old_encoded.get(), old_transformed_element); + + old_encoded.reset(); + + if (old_write_status != C_OK) return old_write_status; - } - Status adjust_status = Adjust(*old_program, new_program); - DeleteAssemblyProgram(old_program); - if (adjust_status != C_OK) { - DeleteAssemblyProgram(new_program); + Status adjust_status = Adjust(*old_program, new_program.get()); + old_program.reset(); + if (adjust_status != C_OK) return adjust_status; - } - EncodedProgram* new_encoded = NULL; - Status new_encode_status = Encode(new_program, &new_encoded); - DeleteAssemblyProgram(new_program); + scoped_ptr<EncodedProgram> new_encoded; + Status new_encode_status = Encode(*new_program, &new_encoded); if (new_encode_status != C_OK) return new_encode_status; - Status new_write_status = - WriteEncodedProgram(new_encoded, new_transformed_element); - DeleteEncodedProgram(new_encoded); - if (new_write_status != C_OK) - return new_write_status; + new_program.reset(); - return C_OK; + Status new_write_status = + WriteEncodedProgram(new_encoded.get(), new_transformed_element); + return new_write_status; } Status Reform(SourceStreamSet* transformed_element, @@ -134,4 +129,5 @@ class PatchGeneratorX86_32 : public TransformationPatchGenerator { }; } // namespace courgette + #endif // COURGETTE_WIN32_X86_GENERATOR_H_ diff --git a/courgette/patcher_x86_32.h b/courgette/patcher_x86_32.h index 28db059..a80ccc3 100644 --- a/courgette/patcher_x86_32.h +++ b/courgette/patcher_x86_32.h @@ -8,7 +8,11 @@ #include <stdint.h> #include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "courgette/assembly_program.h" +#include "courgette/encoded_program.h" #include "courgette/ensemble.h" +#include "courgette/program_detector.h" namespace courgette { @@ -48,39 +52,32 @@ class PatcherX86_32 : public TransformationPatcher { if (!corrected_parameters->Empty()) return C_GENERAL_ERROR; // Don't expect any corrected parameters. - AssemblyProgram* program = NULL; + scoped_ptr<AssemblyProgram> program; status = ParseDetectedExecutable(ensemble_region_.start() + base_offset_, base_length_, &program); if (status != C_OK) return status; - EncodedProgram* encoded = NULL; - status = Encode(program, &encoded); - DeleteAssemblyProgram(program); + scoped_ptr<EncodedProgram> encoded; + status = Encode(*program, &encoded); if (status != C_OK) return status; - status = WriteEncodedProgram(encoded, transformed_element); - DeleteEncodedProgram(encoded); + program.reset(); - return status; + return WriteEncodedProgram(encoded.get(), transformed_element); } Status Reform(SourceStreamSet* transformed_element, SinkStream* reformed_element) { Status status; - EncodedProgram* encoded_program = NULL; + scoped_ptr<EncodedProgram> encoded_program; status = ReadEncodedProgram(transformed_element, &encoded_program); if (status != C_OK) return status; - status = Assemble(encoded_program, reformed_element); - DeleteEncodedProgram(encoded_program); - if (status != C_OK) - return status; - - return C_OK; + return Assemble(encoded_program.get(), reformed_element); } private: @@ -93,4 +90,5 @@ class PatcherX86_32 : public TransformationPatcher { }; } // namespace + #endif // COURGETTE_WIN32_X86_PATCHER_H_ diff --git a/courgette/program_detector.cc b/courgette/program_detector.cc new file mode 100644 index 0000000..e0fe3e6 --- /dev/null +++ b/courgette/program_detector.cc @@ -0,0 +1,85 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "courgette/program_detector.h" + +#include <utility> + +#include "courgette/assembly_program.h" +#include "courgette/disassembler.h" +#include "courgette/disassembler_elf_32_arm.h" +#include "courgette/disassembler_elf_32_x86.h" +#include "courgette/disassembler_win32_x64.h" +#include "courgette/disassembler_win32_x86.h" + +namespace courgette { + +namespace { + +// Returns a new instance of Disassembler subclass if binary data given in +// |buffer| and |length| matches a known binary format, otherwise null. +scoped_ptr<Disassembler> DetectDisassembler(const void* buffer, size_t length) { + scoped_ptr<Disassembler> disassembler; + + disassembler.reset(new DisassemblerWin32X86(buffer, length)); + if (disassembler->ParseHeader()) + return disassembler; + + disassembler.reset(new DisassemblerWin32X64(buffer, length)); + if (disassembler->ParseHeader()) + return disassembler; + + disassembler.reset(new DisassemblerElf32X86(buffer, length)); + if (disassembler->ParseHeader()) + return disassembler; + + disassembler.reset(new DisassemblerElf32ARM(buffer, length)); + if (disassembler->ParseHeader()) + return disassembler; + + return nullptr; +} + +} // namespace + +Status DetectExecutableType(const void* buffer, + size_t length, + ExecutableType* type, + size_t* detected_length) { + scoped_ptr<Disassembler> disassembler(DetectDisassembler(buffer, length)); + + if (!disassembler) { // We failed to detect anything. + *type = EXE_UNKNOWN; + *detected_length = 0; + return C_INPUT_NOT_RECOGNIZED; + } + + *type = disassembler->kind(); + *detected_length = disassembler->length(); + return C_OK; +} + +Status ParseDetectedExecutable(const void* buffer, + size_t length, + scoped_ptr<AssemblyProgram>* output) { + output->reset(); + + scoped_ptr<Disassembler> disassembler(DetectDisassembler(buffer, length)); + if (!disassembler) + return C_INPUT_NOT_RECOGNIZED; + + scoped_ptr<AssemblyProgram> program( + new AssemblyProgram(disassembler->kind())); + + if (!disassembler->Disassemble(program.get())) + return C_DISASSEMBLY_FAILED; + + if (!program->TrimLabels()) + return C_TRIM_FAILED; + + *output = std::move(program); + return C_OK; +} + +} // namespace courgette diff --git a/courgette/program_detector.h b/courgette/program_detector.h new file mode 100644 index 0000000..81b6e2d --- /dev/null +++ b/courgette/program_detector.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COURGETTE_PROGRAM_DETECTOR_H_ +#define COURGETTE_PROGRAM_DETECTOR_H_ + +#include <stddef.h> + +#include "base/memory/scoped_ptr.h" +#include "courgette/courgette.h" + +namespace courgette { + +class AssemblyProgram; + +// Detects the type of an executable file, and it's length. The length may be +// slightly smaller than some executables (like ELF), but will include all bytes +// the courgette algorithm has special benefit for. +// On success: +// Fills in |type| and |detected_length|, and returns C_OK. +// On failure: +// Fills in |type| with UNKNOWN, |detected_length| with 0, and returns +// C_INPUT_NOT_RECOGNIZED. +Status DetectExecutableType(const void* buffer, + size_t length, + ExecutableType* type, + size_t* detected_length); + +// Attempts to detect the type of executable, and parse it with the appropriate +// tools. +// On success: +// Parses the executable into a new AssemblyProgram in |*output|, and returns +// C_OK. +// On failure: +// Returns an error status and assigns |*output| to null. +Status ParseDetectedExecutable(const void* buffer, + size_t length, + scoped_ptr<AssemblyProgram>* output); + +} // namespace courgette + +#endif // COURGETTE_PROGRAM_DETECTOR_H_
\ No newline at end of file |