summaryrefslogtreecommitdiffstats
path: root/courgette
diff options
context:
space:
mode:
authorhuangs <huangs@chromium.org>2016-01-29 14:14:18 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-29 22:15:42 +0000
commit8d5be25a65a341fcbd1b92a6856e8c71600a2bec (patch)
tree69779cd869276371bbdead20859f562fb1c5da0a /courgette
parent7fa91f74858e1a47646814919966b5c5cbf05e92 (diff)
downloadchromium_src-8d5be25a65a341fcbd1b92a6856e8c71600a2bec.zip
chromium_src-8d5be25a65a341fcbd1b92a6856e8c71600a2bec.tar.gz
chromium_src-8d5be25a65a341fcbd1b92a6856e8c71600a2bec.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. Committed: https://crrev.com/0a9cbf1781a114b35a4e0f4a834f2d24ade2e917 Cr-Commit-Position: refs/heads/master@{#372212} Review URL: https://codereview.chromium.org/1629703002 Cr-Commit-Position: refs/heads/master@{#372436}
Diffstat (limited to 'courgette')
-rw-r--r--courgette/BUILD.gn2
-rw-r--r--courgette/adjustment_method_unittest.cc53
-rw-r--r--courgette/assembly_program.cc50
-rw-r--r--courgette/assembly_program.h11
-rw-r--r--courgette/courgette.gyp2
-rw-r--r--courgette/courgette.h36
-rw-r--r--courgette/courgette_tool.cc79
-rw-r--r--courgette/disassembler.cc93
-rw-r--r--courgette/encode_decode_unittest.cc27
-rw-r--r--courgette/encoded_program.cc24
-rw-r--r--courgette/encoded_program.h7
-rw-r--r--courgette/encoded_program_fuzz_unittest.cc28
-rw-r--r--courgette/encoded_program_unittest.cc1
-rw-r--r--courgette/ensemble.cc4
-rw-r--r--courgette/patch_generator_x86_32.h50
-rw-r--r--courgette/patcher_x86_32.h26
-rw-r--r--courgette/program_detector.cc85
-rw-r--r--courgette/program_detector.h43
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