diff options
author | grt <grt@chromium.org> | 2015-11-06 15:06:57 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-06 23:07:42 +0000 |
commit | 825b91ff0d8891c18fe9ee6016c6cde40c9ee983 (patch) | |
tree | 37e5d34216a1853eb1e6e8240217bc26e0aae6b9 /courgette | |
parent | 38cb27903aa3f5a88148e48e4bf3430c5040e3aa (diff) | |
download | chromium_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.cc | 118 | ||||
-rw-r--r-- | courgette/assembly_program.h | 45 | ||||
-rw-r--r-- | courgette/memory_allocator.h | 66 | ||||
-rw-r--r-- | courgette/third_party/paged_array.h | 19 |
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; } } |