summaryrefslogtreecommitdiffstats
path: root/courgette
diff options
context:
space:
mode:
authorgrt <grt@chromium.org>2015-11-06 15:06:57 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-06 23:07:42 +0000
commit825b91ff0d8891c18fe9ee6016c6cde40c9ee983 (patch)
tree37e5d34216a1853eb1e6e8240217bc26e0aae6b9 /courgette
parent38cb27903aa3f5a88148e48e4bf3430c5040e3aa (diff)
downloadchromium_src-825b91ff0d8891c18fe9ee6016c6cde40c9ee983.zip
chromium_src-825b91ff0d8891c18fe9ee6016c6cde40c9ee983.tar.gz
chromium_src-825b91ff0d8891c18fe9ee6016c6cde40c9ee983.tar.bz2
Use base::UncheckedMalloc rather than std::nothrow in courgette.
Allocating via std::nothrow will still crash the process if there's insufficient ram. BUG=530624 Review URL: https://codereview.chromium.org/1429243002 Cr-Commit-Position: refs/heads/master@{#358439}
Diffstat (limited to 'courgette')
-rw-r--r--courgette/assembly_program.cc118
-rw-r--r--courgette/assembly_program.h45
-rw-r--r--courgette/memory_allocator.h66
-rw-r--r--courgette/third_party/paged_array.h19
4 files changed, 147 insertions, 101 deletions
diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc
index 965f457..f050390 100644
--- a/courgette/assembly_program.cc
+++ b/courgette/assembly_program.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "courgette/courgette.h"
@@ -19,39 +20,6 @@
namespace courgette {
-// Opcodes of simple assembly language
-enum OP {
- ORIGIN, // ORIGIN <rva> - set current address for assembly.
- MAKEPERELOCS, // Generates a base relocation table.
- MAKEELFRELOCS, // Generates a base relocation table.
- DEFBYTE, // DEFBYTE <value> - emit a byte literal.
- REL32, // REL32 <label> - emit a rel32 encoded reference to 'label'.
- ABS32, // ABS32 <label> - emit an abs32 encoded reference to 'label'.
- REL32ARM, // REL32ARM <c_op> <label> - arm-specific rel32 reference
- MAKEELFARMRELOCS, // Generates a base relocation table.
- DEFBYTES, // Emits any number of byte literals
- ABS64, // ABS64 <label> - emit an abs64 encoded reference to 'label'.
- LAST_OP
-};
-
-// Base class for instructions. Because we have so many instructions we want to
-// keep them as small as possible. For this reason we avoid virtual functions.
-//
-class Instruction {
- public:
- OP op() const { return static_cast<OP>(op_); }
-
- protected:
- explicit Instruction(OP op) : op_(op), info_(0) {}
- Instruction(OP op, unsigned int info) : op_(op), info_(info) {}
-
- uint32 op_ : 4; // A few bits to store the OP code.
- uint32 info_ : 28; // Remaining bits in first word available to subclass.
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Instruction);
-};
-
namespace {
// Sets the current address for the emitting instructions.
@@ -142,64 +110,67 @@ AssemblyProgram::AssemblyProgram(ExecutableType kind)
static void DeleteContainedLabels(const RVAToLabel& labels) {
for (RVAToLabel::const_iterator p = labels.begin(); p != labels.end(); ++p)
- delete p->second;
+ UncheckedDelete(p->second);
}
AssemblyProgram::~AssemblyProgram() {
for (size_t i = 0; i < instructions_.size(); ++i) {
Instruction* instruction = instructions_[i];
- if (instruction->op() != DEFBYTE) // Will be in byte_instruction_cache_.
- delete instruction;
+ if (instruction->op() != DEFBYTE) // Owned by byte_instruction_cache_.
+ UncheckedDelete(instruction);
}
if (byte_instruction_cache_.get()) {
for (size_t i = 0; i < 256; ++i)
- delete byte_instruction_cache_[i];
+ UncheckedDelete(byte_instruction_cache_[i]);
}
DeleteContainedLabels(rel32_labels_);
DeleteContainedLabels(abs32_labels_);
}
CheckBool AssemblyProgram::EmitPeRelocsInstruction() {
- return Emit(new(std::nothrow) PeRelocsInstruction());
+ return Emit(ScopedInstruction(UncheckedNew<PeRelocsInstruction>()));
}
CheckBool AssemblyProgram::EmitElfRelocationInstruction() {
- return Emit(new(std::nothrow) ElfRelocsInstruction());
+ return Emit(ScopedInstruction(UncheckedNew<ElfRelocsInstruction>()));
}
CheckBool AssemblyProgram::EmitElfARMRelocationInstruction() {
- return Emit(new(std::nothrow) ElfARMRelocsInstruction());
+ return Emit(ScopedInstruction(UncheckedNew<ElfARMRelocsInstruction>()));
}
CheckBool AssemblyProgram::EmitOriginInstruction(RVA rva) {
- return Emit(new(std::nothrow) OriginInstruction(rva));
+ return Emit(ScopedInstruction(UncheckedNew<OriginInstruction>(rva)));
}
CheckBool AssemblyProgram::EmitByteInstruction(uint8 byte) {
- return Emit(GetByteInstruction(byte));
+ return EmitShared(GetByteInstruction(byte));
}
CheckBool AssemblyProgram::EmitBytesInstruction(const uint8* values,
size_t len) {
- return Emit(new(std::nothrow) BytesInstruction(values, len));
+ return Emit(ScopedInstruction(UncheckedNew<BytesInstruction>(values, len)));
}
CheckBool AssemblyProgram::EmitRel32(Label* label) {
- return Emit(new(std::nothrow) InstructionWithLabel(REL32, label));
+ return Emit(
+ ScopedInstruction(UncheckedNew<InstructionWithLabel>(REL32, label)));
}
CheckBool AssemblyProgram::EmitRel32ARM(uint16 op, Label* label,
const uint8* arm_op, uint16 op_size) {
- return Emit(new(std::nothrow) InstructionWithLabelARM(REL32ARM, op, label,
- arm_op, op_size));
+ return Emit(ScopedInstruction(UncheckedNew<InstructionWithLabelARM>(
+ REL32ARM, op, label, arm_op, op_size)));
}
CheckBool AssemblyProgram::EmitAbs32(Label* label) {
- return Emit(new(std::nothrow) InstructionWithLabel(ABS32, label));
+ return Emit(
+ ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS32, label)));
}
CheckBool AssemblyProgram::EmitAbs64(Label* label) {
- return Emit(new (std::nothrow) InstructionWithLabel(ABS64, label));
+ return Emit(
+ ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS64, label)));
}
Label* AssemblyProgram::FindOrMakeAbs32Label(RVA rva) {
@@ -249,19 +220,23 @@ Label* AssemblyProgram::InstructionRel32Label(
return NULL;
}
-CheckBool AssemblyProgram::Emit(Instruction* instruction) {
- if (!instruction)
+CheckBool AssemblyProgram::Emit(ScopedInstruction instruction) {
+ if (!instruction || !instructions_.push_back(instruction.get()))
return false;
- bool ok = instructions_.push_back(instruction);
- if (!ok)
- delete instruction;
- return ok;
+ // Ownership successfully passed to instructions_.
+ ignore_result(instruction.release());
+ return true;
+}
+
+CheckBool AssemblyProgram::EmitShared(Instruction* instruction) {
+ DCHECK(!instruction || instruction->op() == DEFBYTE);
+ return instruction && instructions_.push_back(instruction);
}
Label* AssemblyProgram::FindLabel(RVA rva, RVAToLabel* labels) {
Label*& slot = (*labels)[rva];
if (slot == NULL) {
- slot = new(std::nothrow) Label(rva);
+ slot = UncheckedNew<Label>(rva);
if (slot == NULL)
return NULL;
}
@@ -401,9 +376,7 @@ static CheckBool DefineLabels(const RVAToLabel& labels,
}
EncodedProgram* AssemblyProgram::Encode() const {
- scoped_ptr<EncodedProgram> encoded(new(std::nothrow) EncodedProgram());
- if (!encoded.get())
- return NULL;
+ scoped_ptr<EncodedProgram> encoded(new EncodedProgram());
encoded->set_image_base(image_base_);
@@ -494,19 +467,22 @@ EncodedProgram* AssemblyProgram::Encode() const {
}
Instruction* AssemblyProgram::GetByteInstruction(uint8 byte) {
- if (!byte_instruction_cache_.get()) {
- byte_instruction_cache_.reset(new(std::nothrow) Instruction*[256]);
- if (!byte_instruction_cache_.get())
- return NULL;
+ if (!byte_instruction_cache_) {
+ Instruction** ram = nullptr;
+ if (!base::UncheckedMalloc(sizeof(Instruction*) * 256,
+ reinterpret_cast<void**>(&ram))) {
+ return nullptr;
+ }
+ byte_instruction_cache_.reset(ram);
for (int i = 0; i < 256; ++i) {
byte_instruction_cache_[i] =
- new(std::nothrow) ByteInstruction(static_cast<uint8>(i));
+ UncheckedNew<ByteInstruction>(static_cast<uint8>(i));
if (!byte_instruction_cache_[i]) {
for (int j = 0; j < i; ++j)
- delete byte_instruction_cache_[j];
+ UncheckedDelete(byte_instruction_cache_[j]);
byte_instruction_cache_.reset();
- return NULL;
+ return nullptr;
}
}
}
@@ -531,6 +507,10 @@ CheckBool AssemblyProgram::TrimLabels() {
RVAToLabel::iterator it = rel32_labels_.begin();
while (it != rel32_labels_.end()) {
if (it->second->count_ <= lower_limit) {
+ // Note: it appears to me (grt) that this leaks the Label instances. I
+ // *think* the right thing would be to add it->second to a collection for
+ // which all elements are freed via UncheckedDelete after the instruction
+ // fixup loop below.
rel32_labels_.erase(it++);
} else {
++it;
@@ -553,10 +533,10 @@ CheckBool AssemblyProgram::TrimLabels() {
if (op_size < 1)
return false;
- BytesInstruction* new_instruction =
- new(std::nothrow) BytesInstruction(arm_op, op_size);
- instructions_[i] = new_instruction;
- delete instruction;
+ UncheckedDelete(instruction);
+ instructions_[i] = UncheckedNew<BytesInstruction>(arm_op, op_size);
+ if (!instructions_[i])
+ return false;
}
break;
}
diff --git a/courgette/assembly_program.h b/courgette/assembly_program.h
index 096cc4d..ba7ad59f18 100644
--- a/courgette/assembly_program.h
+++ b/courgette/assembly_program.h
@@ -18,9 +18,6 @@
namespace courgette {
class EncodedProgram;
-class Instruction;
-
-typedef NoThrowBuffer<Instruction*> InstructionVector;
// A Label is a symbolic reference to an address. Unlike a conventional
// assembly language, we always know the address. The address will later be
@@ -41,6 +38,40 @@ class Label {
typedef std::map<RVA, Label*> RVAToLabel;
+// Opcodes of simple assembly language
+enum OP {
+ ORIGIN, // ORIGIN <rva> - set current address for assembly.
+ MAKEPERELOCS, // Generates a base relocation table.
+ MAKEELFRELOCS, // Generates a base relocation table.
+ DEFBYTE, // DEFBYTE <value> - emit a byte literal.
+ REL32, // REL32 <label> - emit a rel32 encoded reference to 'label'.
+ ABS32, // ABS32 <label> - emit an abs32 encoded reference to 'label'.
+ REL32ARM, // REL32ARM <c_op> <label> - arm-specific rel32 reference
+ MAKEELFARMRELOCS, // Generates a base relocation table.
+ DEFBYTES, // Emits any number of byte literals
+ ABS64, // ABS64 <label> - emit an abs64 encoded reference to 'label'.
+ LAST_OP
+};
+
+// Base class for instructions. Because we have so many instructions we want to
+// keep them as small as possible. For this reason we avoid virtual functions.
+class Instruction {
+ public:
+ OP op() const { return static_cast<OP>(op_); }
+
+ protected:
+ explicit Instruction(OP op) : op_(op), info_(0) {}
+ Instruction(OP op, unsigned int info) : op_(op), info_(info) {}
+
+ uint32 op_ : 4; // A few bits to store the OP code.
+ uint32 info_ : 28; // Remaining bits in first word available to subclass.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Instruction);
+};
+
+typedef NoThrowBuffer<Instruction*> InstructionVector;
+
// An AssemblyProgram is the result of disassembling an executable file.
//
// * The disassembler creates labels in the AssemblyProgram and emits
@@ -137,9 +168,13 @@ class AssemblyProgram {
CheckBool TrimLabels();
private:
+ using ScopedInstruction =
+ scoped_ptr<Instruction, UncheckedDeleter<Instruction>>;
+
ExecutableType kind_;
- CheckBool Emit(Instruction* instruction) WARN_UNUSED_RESULT;
+ CheckBool Emit(ScopedInstruction instruction) WARN_UNUSED_RESULT;
+ CheckBool EmitShared(Instruction* instruction) WARN_UNUSED_RESULT;
static const int kLabelLowerLimit;
@@ -153,7 +188,7 @@ class AssemblyProgram {
// Sharing instructions that emit a single byte saves a lot of space.
Instruction* GetByteInstruction(uint8 byte);
- scoped_ptr<Instruction*[]> byte_instruction_cache_;
+ scoped_ptr<Instruction* [], base::FreeDeleter> byte_instruction_cache_;
uint64 image_base_; // Desired or mandated base address of image.
diff --git a/courgette/memory_allocator.h b/courgette/memory_allocator.h
index 15b709e..7161592 100644
--- a/courgette/memory_allocator.h
+++ b/courgette/memory_allocator.h
@@ -5,12 +5,14 @@
#ifndef COURGETTE_MEMORY_ALLOCATOR_H_
#define COURGETTE_MEMORY_ALLOCATOR_H_
-#include <memory>
+#include <stdlib.h>
#include "base/basictypes.h"
+#include "base/compiler_specific.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/process/memory.h"
#ifndef NDEBUG
@@ -55,6 +57,31 @@ typedef bool CheckBool;
namespace courgette {
+// Allocates memory for an instance of type T, instantiates an object in that
+// memory with arguments |args| (of type ArgTypes), and returns the constructed
+// instance. Returns null if allocation fails.
+template <class T, class... ArgTypes>
+T* UncheckedNew(ArgTypes... args) {
+ void* ram = nullptr;
+ return base::UncheckedMalloc(sizeof(T), &ram) ? new (ram) T(args...)
+ : nullptr;
+}
+
+// Complement of UncheckedNew(): destructs |object| and releases its memory.
+template <class T>
+void UncheckedDelete(T* object) {
+ if (object) {
+ object->T::~T();
+ free(object);
+ }
+}
+
+// A deleter for scoped_ptr that will delete the object via UncheckedDelete().
+template <class T>
+struct UncheckedDeleter {
+ inline void operator()(T* ptr) const { UncheckedDelete(ptr); }
+};
+
#if defined(OS_WIN)
// Manages a read/write virtual mapping of a physical file.
@@ -170,11 +197,10 @@ class MemoryAllocator {
uint8* mem = reinterpret_cast<uint8*>(ptr);
mem -= sizeof(T);
if (mem[0] == HEAP_ALLOCATION) {
- delete [] mem;
+ free(mem);
} else {
DCHECK_EQ(static_cast<uint8>(FILE_ALLOCATION), mem[0]);
- TempMapping* mapping = TempMapping::GetMappingFromPtr(mem);
- delete mapping;
+ UncheckedDelete(TempMapping::GetMappingFromPtr(mem));
}
}
@@ -192,17 +218,20 @@ class MemoryAllocator {
uint8* mem = NULL;
// First see if we can do this allocation on the heap.
- if (count < kMaxHeapAllocationSize)
- mem = new(std::nothrow) uint8[bytes];
- if (mem != NULL) {
+ if (count < kMaxHeapAllocationSize &&
+ base::UncheckedMalloc(bytes, reinterpret_cast<void**>(&mem))) {
mem[0] = static_cast<uint8>(HEAP_ALLOCATION);
} else {
- // If either the heap allocation failed or the request exceeds the
- // max heap allocation threshold, we back the allocation with a temp file.
- TempMapping* mapping = new(std::nothrow) TempMapping();
- if (mapping && mapping->Initialize(bytes)) {
- mem = reinterpret_cast<uint8*>(mapping->memory());
- mem[0] = static_cast<uint8>(FILE_ALLOCATION);
+ // Back the allocation with a temp file if either the request exceeds the
+ // max heap allocation threshold or the heap allocation failed.
+ TempMapping* mapping = UncheckedNew<TempMapping>();
+ if (mapping) {
+ if (mapping->Initialize(bytes)) {
+ mem = reinterpret_cast<uint8*>(mapping->memory());
+ mem[0] = static_cast<uint8>(FILE_ALLOCATION);
+ } else {
+ UncheckedDelete(mapping);
+ }
}
}
return mem ? reinterpret_cast<pointer>(mem + sizeof(T)) : NULL;
@@ -260,15 +289,16 @@ class MemoryAllocator {
~MemoryAllocator() {
}
- void deallocate(pointer ptr, size_type size) {
- delete [] ptr;
- }
+ void deallocate(pointer ptr, size_type size) { free(ptr); }
pointer allocate(size_type count) {
if (count > max_size())
return NULL;
- return reinterpret_cast<pointer>(
- new(std::nothrow) uint8[count * sizeof(T)]);
+ pointer result = nullptr;
+ return base::UncheckedMalloc(count * sizeof(T),
+ reinterpret_cast<void**>(&result))
+ ? result
+ : nullptr;
}
pointer allocate(size_type count, const void* hint) {
diff --git a/courgette/third_party/paged_array.h b/courgette/third_party/paged_array.h
index b12b695..76cb879 100644
--- a/courgette/third_party/paged_array.h
+++ b/courgette/third_party/paged_array.h
@@ -7,13 +7,12 @@
// PagedArray is a work-around to allow large arrays to be allocated when there
// is too much address space fragmentation for allocating the large arrays as
// contigous arrays.
+
#ifndef COURGETTE_BSDIFF_PAGED_ARRAY_H_
#define COURGETTE_BSDIFF_PAGED_ARRAY_H_
-// For std::nothrow:
-#include <new>
-
#include "base/basictypes.h"
+#include "base/process/memory.h"
namespace courgette {
@@ -44,13 +43,15 @@ class PagedArray {
bool Allocate(size_t size) {
clear();
size_t pages_needed = (size + kPageSize - 1) >> kLogPageSize;
- pages_ = new(std::nothrow) T*[pages_needed];
- if (pages_ == NULL)
+ if (!base::UncheckedMalloc(sizeof(T*) * pages_needed,
+ reinterpret_cast<void**>(&pages_))) {
return false;
+ }
for (page_count_ = 0; page_count_ < pages_needed; ++page_count_) {
- T* block = new(std::nothrow) T[kPageSize];
- if (block == NULL) {
+ T* block = nullptr;
+ if (!base::UncheckedMalloc(sizeof(T) * kPageSize,
+ reinterpret_cast<void**>(&block))) {
clear();
return false;
}
@@ -64,9 +65,9 @@ class PagedArray {
if (pages_ != NULL) {
while (page_count_ != 0) {
--page_count_;
- delete[] pages_[page_count_];
+ free(pages_[page_count_]);
}
- delete[] pages_;
+ free(pages_);
pages_ = NULL;
}
}