diff options
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 3 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.cc | 11 | ||||
-rw-r--r-- | chrome/installer/util/util_constants.h | 1 | ||||
-rw-r--r-- | courgette/adjustment_method.cc | 6 | ||||
-rw-r--r-- | courgette/adjustment_method_2.cc | 4 | ||||
-rw-r--r-- | courgette/adjustment_method_unittest.cc | 14 | ||||
-rw-r--r-- | courgette/assembly_program.cc | 60 | ||||
-rw-r--r-- | courgette/assembly_program.h | 26 | ||||
-rw-r--r-- | courgette/courgette_tool.cc | 39 | ||||
-rw-r--r-- | courgette/disassembler.cc | 68 | ||||
-rw-r--r-- | courgette/encode_decode_unittest.cc | 4 | ||||
-rw-r--r-- | courgette/encoded_program.cc | 154 | ||||
-rw-r--r-- | courgette/encoded_program.h | 34 | ||||
-rw-r--r-- | courgette/ensemble_apply.cc | 4 | ||||
-rw-r--r-- | courgette/ensemble_create.cc | 27 | ||||
-rw-r--r-- | courgette/memory_allocator.cc | 75 | ||||
-rw-r--r-- | courgette/memory_allocator.h | 281 | ||||
-rw-r--r-- | courgette/streams.cc | 9 | ||||
-rw-r--r-- | courgette/streams.h | 32 | ||||
-rw-r--r-- | courgette/win32_x86_generator.h | 7 | ||||
-rw-r--r-- | courgette/win32_x86_patcher.h | 4 |
21 files changed, 565 insertions, 298 deletions
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 87cf8a5..15d04e1 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -510,7 +510,8 @@ installer::InstallStatus InstallProductsHelper( FilePath unpack_path(temp_path.path().Append(installer::kInstallSourceDir)); if (UnPackArchive(archive, installer_state, temp_path.path(), unpack_path, archive_type)) { - install_status = installer::UNCOMPRESSION_FAILED; + install_status = (*archive_type) == installer::INCREMENTAL_ARCHIVE_TYPE ? + installer::APPLY_DIFF_PATCH_FAILED : installer::UNCOMPRESSION_FAILED; InstallUtil::WriteInstallerResult(system_install, installer_state.state_key(), install_status, IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc index dbe895c..19b6ce3 100644 --- a/chrome/installer/setup/setup_util.cc +++ b/chrome/installer/setup/setup_util.cc @@ -35,7 +35,16 @@ int ApplyDiffPatch(const FilePath& src, if (patch_status == courgette::C_OK) return 0; - VLOG(1) << "Failed to apply patch " << patch.value() << " using courgette."; + VLOG(1) << "Failed to apply patch " << patch.value() + << " using courgette. err=" << patch_status; + + // If we ran out of memory or disk space, then these are likely the errors + // we will see. If we run into them, return an error and stay on the + // 'ENSEMBLE_PATCHING' update stage. + if (patch_status == courgette::C_DISASSEMBLY_FAILED || + patch_status == courgette::C_STREAM_ERROR) { + return MEM_ERROR; + } if (installer_state != NULL) installer_state->UpdateStage(installer::BINARY_PATCHING); diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index c8bcc3d..9153b7b 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -73,6 +73,7 @@ enum InstallStatus { READY_MODE_REQUIRES_CHROME, // 40. Chrome Frame in ready-mode requires Chrome REQUIRES_MULTI_INSTALL, // 41. --multi-install was missing from the // command line. + APPLY_DIFF_PATCH_FAILED, // 42. Failed to apply a diff patch. }; diff --git a/courgette/adjustment_method.cc b/courgette/adjustment_method.cc index 7913f8c..520f2a0 100644 --- a/courgette/adjustment_method.cc +++ b/courgette/adjustment_method.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -597,7 +597,7 @@ class GraphAdjuster : public AdjustmentMethod { bool is_model) { const InstructionVector& instructions = program->instructions(); for (size_t i = 0; i < instructions.size(); ++i) { - Instruction* instruction = instructions.at(i); + Instruction* instruction = instructions[i]; if (Label* label = program->InstructionAbs32Label(instruction)) ReferenceLabel(abs32, label, is_model); if (Label* label = program->InstructionRel32Label(instruction)) @@ -607,7 +607,7 @@ class GraphAdjuster : public AdjustmentMethod { // incorporate some costing for entropy (bigger deltas) that will be // introduced into the label address table by non-monotonic ordering. This // would have some knock-on effects to parts of the algorithm that work on - // single-occurence labels. + // single-occurrence labels. } void Solve(const Trace& model, const Trace& problem) { diff --git a/courgette/adjustment_method_2.cc b/courgette/adjustment_method_2.cc index 4a3d1c1..e4fd716 100644 --- a/courgette/adjustment_method_2.cc +++ b/courgette/adjustment_method_2.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -1254,7 +1254,7 @@ class Adjuster : public AdjustmentMethod { label_info_maker_.ResetDebugLabel(); const InstructionVector& instructions = program->instructions(); for (size_t i = 0; i < instructions.size(); ++i) { - Instruction* instruction = instructions.at(i); + Instruction* instruction = instructions[i]; if (Label* label = program->InstructionAbs32Label(instruction)) ReferenceLabel(abs32, label, is_model); if (Label* label = program->InstructionRel32Label(instruction)) diff --git a/courgette/adjustment_method_unittest.cc b/courgette/adjustment_method_unittest.cc index 661b23d..8f5395b 100644 --- a/courgette/adjustment_method_unittest.cc +++ b/courgette/adjustment_method_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -34,12 +34,12 @@ class AdjustmentMethodTest : public testing::Test { courgette::Label* labelA = prog->FindOrMakeAbs32Label(0x00410000); courgette::Label* labelB = prog->FindOrMakeAbs32Label(0x00410004); - prog->EmitAbs32(labelA); - prog->EmitAbs32(labelA); - prog->EmitAbs32(labelB); - prog->EmitAbs32(labelA); - prog->EmitAbs32(labelA); - prog->EmitAbs32(labelB); + EXPECT_TRUE(prog->EmitAbs32(labelA)); + EXPECT_TRUE(prog->EmitAbs32(labelA)); + EXPECT_TRUE(prog->EmitAbs32(labelB)); + EXPECT_TRUE(prog->EmitAbs32(labelA)); + EXPECT_TRUE(prog->EmitAbs32(labelA)); + EXPECT_TRUE(prog->EmitAbs32(labelB)); if (kind == 0) { labelA->index_ = 0; diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc index 080a89e..f759e16 100644 --- a/courgette/assembly_program.cc +++ b/courgette/assembly_program.cc @@ -86,8 +86,7 @@ class InstructionWithLabel : public Instruction { } // namespace AssemblyProgram::AssemblyProgram() - : byte_instruction_cache_(NULL), - image_base_(0) { + : image_base_(0) { } static void DeleteContainedLabels(const RVAToLabel& labels) { @@ -101,33 +100,32 @@ AssemblyProgram::~AssemblyProgram() { if (instruction->op() != DEFBYTE) // Will be in byte_instruction_cache_. delete instruction; } - if (byte_instruction_cache_) { + if (byte_instruction_cache_.get()) { for (size_t i = 0; i < 256; ++i) delete byte_instruction_cache_[i]; - delete[] byte_instruction_cache_; } DeleteContainedLabels(rel32_labels_); DeleteContainedLabels(abs32_labels_); } -void AssemblyProgram::EmitMakeRelocsInstruction() { - Emit(new MakeRelocsInstruction()); +CheckBool AssemblyProgram::EmitMakeRelocsInstruction() { + return Emit(new(std::nothrow) MakeRelocsInstruction()); } -void AssemblyProgram::EmitOriginInstruction(RVA rva) { - Emit(new OriginInstruction(rva)); +CheckBool AssemblyProgram::EmitOriginInstruction(RVA rva) { + return Emit(new(std::nothrow) OriginInstruction(rva)); } -void AssemblyProgram::EmitByteInstruction(uint8 byte) { - Emit(GetByteInstruction(byte)); +CheckBool AssemblyProgram::EmitByteInstruction(uint8 byte) { + return Emit(GetByteInstruction(byte)); } -void AssemblyProgram::EmitRel32(Label* label) { - Emit(new InstructionWithLabel(REL32, label)); +CheckBool AssemblyProgram::EmitRel32(Label* label) { + return Emit(new(std::nothrow) InstructionWithLabel(REL32, label)); } -void AssemblyProgram::EmitAbs32(Label* label) { - Emit(new InstructionWithLabel(ABS32, label)); +CheckBool AssemblyProgram::EmitAbs32(Label* label) { + return Emit(new(std::nothrow) InstructionWithLabel(ABS32, label)); } Label* AssemblyProgram::FindOrMakeAbs32Label(RVA rva) { @@ -167,10 +165,19 @@ Label* AssemblyProgram::InstructionRel32Label( return NULL; } +CheckBool AssemblyProgram::Emit(Instruction* instruction) { + if (!instruction) + return false; + bool ok = instructions_.push_back(instruction); + if (!ok) + delete instruction; + return ok; +} + Label* AssemblyProgram::FindLabel(RVA rva, RVAToLabel* labels) { Label*& slot = (*labels)[rva]; - if (slot == 0) { - slot = new Label(rva); + if (slot == NULL) { + slot = new(std::nothrow) Label(rva); } return slot; } @@ -307,7 +314,10 @@ static CheckBool DefineLabels(const RVAToLabel& labels, } EncodedProgram* AssemblyProgram::Encode() const { - scoped_ptr<EncodedProgram> encoded(new EncodedProgram()); + scoped_ptr<EncodedProgram> encoded(new(std::nothrow) EncodedProgram()); + if (!encoded.get()) + return NULL; + encoded->set_image_base(image_base_); if (!DefineLabels(abs32_labels_, encoded.get(), @@ -362,10 +372,20 @@ EncodedProgram* AssemblyProgram::Encode() const { } Instruction* AssemblyProgram::GetByteInstruction(uint8 byte) { - if (!byte_instruction_cache_) { - byte_instruction_cache_ = new Instruction*[256]; + if (!byte_instruction_cache_.get()) { + byte_instruction_cache_.reset(new(std::nothrow) Instruction*[256]); + if (!byte_instruction_cache_.get()) + return NULL; + for (int i = 0; i < 256; ++i) { - byte_instruction_cache_[i] = new ByteInstruction(static_cast<uint8>(i)); + byte_instruction_cache_[i] = + new(std::nothrow) ByteInstruction(static_cast<uint8>(i)); + if (!byte_instruction_cache_[i]) { + for (int j = 0; j < i; ++j) + delete byte_instruction_cache_[j]; + byte_instruction_cache_.reset(); + return NULL; + } } } diff --git a/courgette/assembly_program.h b/courgette/assembly_program.h index f7429201..0d865f5 100644 --- a/courgette/assembly_program.h +++ b/courgette/assembly_program.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -10,6 +10,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "courgette/image_info.h" #include "courgette/memory_allocator.h" @@ -19,8 +20,7 @@ namespace courgette { class EncodedProgram; class Instruction; -typedef std::vector<Instruction*, MemoryAllocator<Instruction*> > - InstructionVector; +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 @@ -34,7 +34,7 @@ class Label { Label() : rva_(0), index_(kNoIndex) {} explicit Label(RVA rva) : rva_(rva), index_(kNoIndex) {} - RVA rva_; // Address refered to by the label. + RVA rva_; // Address referred to by the label. int index_; // Index of address in address table, kNoIndex until assigned. }; @@ -69,21 +69,24 @@ class AssemblyProgram { // Instructions will be assembled in the order they are emitted. // Generates an entire base relocation table. - void EmitMakeRelocsInstruction(); + CheckBool EmitMakeRelocsInstruction() WARN_UNUSED_RESULT; // Following instruction will be assembled at address 'rva'. - void EmitOriginInstruction(RVA rva); + CheckBool EmitOriginInstruction(RVA rva) WARN_UNUSED_RESULT; // Generates a single byte of data or machine instruction. - void EmitByteInstruction(uint8 byte); + CheckBool EmitByteInstruction(uint8 byte) WARN_UNUSED_RESULT; // Generates 4-byte relative reference to address of 'label'. - void EmitRel32(Label* label); + CheckBool EmitRel32(Label* label) WARN_UNUSED_RESULT; // Generates 4-byte absolute reference to address of 'label'. - void EmitAbs32(Label* label); + CheckBool EmitAbs32(Label* label) WARN_UNUSED_RESULT; + // Looks up a label or creates a new one. Might return NULL. Label* FindOrMakeAbs32Label(RVA rva); + + // Looks up a label or creates a new one. Might return NULL. Label* FindOrMakeRel32Label(RVA rva); void DefaultAssignIndexes(); @@ -106,8 +109,9 @@ class AssemblyProgram { Label* InstructionRel32Label(const Instruction* instruction) const; private: - void Emit(Instruction* instruction) { instructions_.push_back(instruction); } + CheckBool Emit(Instruction* instruction) WARN_UNUSED_RESULT; + // Looks up a label or creates a new one. Might return NULL. Label* FindLabel(RVA rva, RVAToLabel* labels); // Helper methods for the public versions. @@ -117,7 +121,7 @@ class AssemblyProgram { // Sharing instructions that emit a single byte saves a lot of space. Instruction* GetByteInstruction(uint8 byte); - Instruction** byte_instruction_cache_; + scoped_array<Instruction*> byte_instruction_cache_; uint64 image_base_; // Desired or mandated base address of image. diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc index 523a438..225906e 100644 --- a/courgette/courgette_tool.cc +++ b/courgette/courgette_tool.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -303,20 +303,39 @@ void ApplyEnsemblePatch(const std::wstring& old_file, #endif courgette::Status status = - courgette::ApplyEnsemblePatch(old_path.value().c_str(), - patch_path.value().c_str(), - new_path.value().c_str()); + courgette::ApplyEnsemblePatch(old_path.value().c_str(), + patch_path.value().c_str(), + new_path.value().c_str()); if (status == courgette::C_OK) return; // Diagnose the error. - if (status == courgette::C_BAD_ENSEMBLE_MAGIC) - Problem("Not a courgette patch"); - if (status == courgette::C_BAD_ENSEMBLE_VERSION) - Problem("Wrong version patch"); - if (status == courgette::C_BAD_ENSEMBLE_HEADER) - Problem("Corrupt patch"); + switch (status) { + case courgette::C_BAD_ENSEMBLE_MAGIC: + Problem("Not a courgette patch"); + break; + + case courgette::C_BAD_ENSEMBLE_VERSION: + Problem("Wrong version patch"); + break; + + case courgette::C_BAD_ENSEMBLE_HEADER: + Problem("Corrupt patch"); + break; + + case courgette::C_DISASSEMBLY_FAILED: + Problem("Disassembly failed (could be because of memory issues)"); + break; + + case courgette::C_STREAM_ERROR: + Problem("Stream error (likely out of memory or disk space)"); + break; + + default: + break; + } + // If we failed due to a missing input file, this will // print the message. std::string old_buffer = ReadOrFail(old_file, "'old' input"); diff --git a/courgette/disassembler.cc b/courgette/disassembler.cc index 2b4db2c..e3dd71a 100644 --- a/courgette/disassembler.cc +++ b/courgette/disassembler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -36,17 +36,16 @@ class DisassemblerWin32X86 : public Disassembler { protected: PEInfo& pe_info() { return *pe_info_; } - void ParseFile(AssemblyProgram* target); + CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT; bool ParseAbs32Relocs(); void ParseRel32RelocsFromSections(); void ParseRel32RelocsFromSection(const Section* section); - void ParseNonSectionFileRegion(uint32 start_file_offset, - uint32 end_file_offset, - AssemblyProgram* program); - void ParseFileRegion(const Section* section, - uint32 start_file_offset, uint32 end_file_offset, - AssemblyProgram* program); + CheckBool ParseNonSectionFileRegion(uint32 start_file_offset, + uint32 end_file_offset, AssemblyProgram* program) WARN_UNUSED_RESULT; + CheckBool ParseFileRegion(const Section* section, + uint32 start_file_offset, uint32 end_file_offset, + AssemblyProgram* program) WARN_UNUSED_RESULT; #if COURGETTE_HISTOGRAM_TARGETS void HistogramTargets(const char* kind, const std::map<RVA, int>& map); @@ -75,9 +74,11 @@ bool DisassemblerWin32X86::Disassemble(AssemblyProgram* target) { ParseRel32RelocsFromSections(); - ParseFile(target); + if (!ParseFile(target)) + return false; target->DefaultAssignIndexes(); + return true; } @@ -228,10 +229,11 @@ void DisassemblerWin32X86::ParseRel32RelocsFromSection(const Section* section) { } } -void DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { +CheckBool DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { + bool ok = true; // Walk all the bytes in the file, whether or not in a section. uint32 file_offset = 0; - while (file_offset < pe_info().length()) { + while (ok && file_offset < pe_info().length()) { const Section* section = pe_info().FindNextSection(file_offset); if (section == NULL) { // No more sections. There should not be extra stuff following last @@ -241,39 +243,47 @@ void DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { } if (file_offset < section->file_offset_of_raw_data) { uint32 section_start_offset = section->file_offset_of_raw_data; - ParseNonSectionFileRegion(file_offset, section_start_offset, program); + ok = ParseNonSectionFileRegion(file_offset, section_start_offset, + program); file_offset = section_start_offset; } - uint32 end = file_offset + section->size_of_raw_data; - ParseFileRegion(section, file_offset, end, program); - file_offset = end; + if (ok) { + uint32 end = file_offset + section->size_of_raw_data; + ok = ParseFileRegion(section, file_offset, end, program); + file_offset = end; + } } #if COURGETTE_HISTOGRAM_TARGETS HistogramTargets("abs32 relocs", abs32_target_rvas_); HistogramTargets("rel32 relocs", rel32_target_rvas_); #endif + + return ok; } -void DisassemblerWin32X86::ParseNonSectionFileRegion( +CheckBool DisassemblerWin32X86::ParseNonSectionFileRegion( uint32 start_file_offset, uint32 end_file_offset, AssemblyProgram* program) { if (incomplete_disassembly_) - return; + return true; const uint8* start = pe_info().FileOffsetToPointer(start_file_offset); const uint8* end = pe_info().FileOffsetToPointer(end_file_offset); const uint8* p = start; - while (p < end) { - program->EmitByteInstruction(*p); + bool ok = true; + while (p < end && ok) { + ok = program->EmitByteInstruction(*p); ++p; } + + return ok; } -void DisassemblerWin32X86::ParseFileRegion( +CheckBool DisassemblerWin32X86::ParseFileRegion( const Section* section, uint32 start_file_offset, uint32 end_file_offset, AssemblyProgram* program) { @@ -292,18 +302,20 @@ void DisassemblerWin32X86::ParseFileRegion( std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); - program->EmitOriginInstruction(start_rva); + bool ok = program->EmitOriginInstruction(start_rva); const uint8* p = start_pointer; - while (p < end_pointer) { + while (ok && p < end_pointer) { RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); // The base relocation table is usually in the .relocs section, but it could // actually be anywhere. Make sure we skip it because we will regenerate it // during assembly. if (current_rva == relocs_start_rva) { - program->EmitMakeRelocsInstruction(); + ok = program->EmitMakeRelocsInstruction(); + if (!ok) + break; uint32 relocs_size = pe_info().base_relocation_table().size_; if (relocs_size) { p += relocs_size; @@ -319,7 +331,9 @@ void DisassemblerWin32X86::ParseFileRegion( RVA target_rva = target_address - pe_info().image_base(); // TODO(sra): target could be Label+offset. It is not clear how to guess // which it might be. We assume offset==0. - program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva)); + ok = program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva)); + if (!ok) + break; p += 4; continue; } @@ -329,7 +343,7 @@ void DisassemblerWin32X86::ParseFileRegion( if (rel32_pos != rel32_locations_.end() && *rel32_pos == current_rva) { RVA target_rva = current_rva + 4 + Read32LittleEndian(p); - program->EmitRel32(program->FindOrMakeRel32Label(target_rva)); + ok = program->EmitRel32(program->FindOrMakeRel32Label(target_rva)); p += 4; continue; } @@ -343,9 +357,11 @@ void DisassemblerWin32X86::ParseFileRegion( } } - program->EmitByteInstruction(*p); + ok = program->EmitByteInstruction(*p); p += 1; } + + return ok; } #if COURGETTE_HISTOGRAM_TARGETS diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc index 2396938..c14dc9f 100644 --- a/courgette/encode_decode_unittest.cc +++ b/courgette/encode_decode_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -53,7 +53,7 @@ void EncodeDecodeTest::TestExe(const char* file_name) const { courgette::AssemblyProgram* program = NULL; const courgette::Status parse_status = - courgette::ParseWin32X86PE(original_buffer, original_length, &program); + courgette::ParseWin32X86PE(original_buffer, original_length, &program); EXPECT_EQ(courgette::C_OK, parse_status); courgette::EncodedProgram* encoded = NULL; diff --git a/courgette/encoded_program.cc b/courgette/encoded_program.cc index a479a40..a675dc2 100644 --- a/courgette/encoded_program.cc +++ b/courgette/encoded_program.cc @@ -33,46 +33,46 @@ const int kStreamOriginAddresses = kStreamMisc; const int kStreamLimit = 9; // Constructor is here rather than in the header. Although the constructor -// appears to do nothing it is fact quite large because of the implict calls to +// appears to do nothing it is fact quite large because of the implicit calls to // field constructors. Ditto for the destructor. EncodedProgram::EncodedProgram() : image_base_(0) {} EncodedProgram::~EncodedProgram() {} // Serializes a vector of integral values using Varint32 coding. -template<typename T, typename A> -CheckBool WriteVector(const std::vector<T, A>& items, SinkStream* buffer) { +template<typename V> +CheckBool WriteVector(const V& items, SinkStream* buffer) { size_t count = items.size(); bool ok = buffer->WriteSizeVarint32(count); for (size_t i = 0; ok && i < count; ++i) { - COMPILE_ASSERT(sizeof(T) <= sizeof(uint32), // NOLINT + COMPILE_ASSERT(sizeof(items[0]) <= sizeof(uint32), // NOLINT T_must_fit_in_uint32); ok = buffer->WriteSizeVarint32(items[i]); } return ok; } -template<typename T, typename A> -bool ReadVector(std::vector<T, A>* items, SourceStream* buffer) { +template<typename V> +bool ReadVector(V* items, SourceStream* buffer) { uint32 count; if (!buffer->ReadVarint32(&count)) return false; items->clear(); - items->reserve(count); - for (size_t i = 0; i < count; ++i) { + + bool ok = items->reserve(count); + for (size_t i = 0; ok && i < count; ++i) { uint32 item; - if (!buffer->ReadVarint32(&item)) - return false; - // TODO(tommi): Handle errors. - items->push_back(static_cast<T>(item)); + ok = buffer->ReadVarint32(&item); + if (ok) + ok = items->push_back(static_cast<typename V::value_type>(item)); } - return true; + return ok; } // Serializes a vector, using delta coding followed by Varint32 coding. -template<typename A> -CheckBool WriteU32Delta(const std::vector<uint32, A>& set, SinkStream* buffer) { +template<typename V> +CheckBool WriteU32Delta(const V& set, SinkStream* buffer) { size_t count = set.size(); bool ok = buffer->WriteSizeVarint32(count); uint32 prev = 0; @@ -85,65 +85,61 @@ CheckBool WriteU32Delta(const std::vector<uint32, A>& set, SinkStream* buffer) { return ok; } -template <typename A> -static CheckBool ReadU32Delta(std::vector<uint32, A>* set, - SourceStream* buffer) { +template <typename V> +static CheckBool ReadU32Delta(V* set, SourceStream* buffer) { uint32 count; if (!buffer->ReadVarint32(&count)) return false; set->clear(); - // TODO(tommi): Handle errors. - set->reserve(count); + bool ok = set->reserve(count); uint32 prev = 0; - for (size_t i = 0; i < count; ++i) { + for (size_t i = 0; ok && i < count; ++i) { uint32 delta; - if (!buffer->ReadVarint32(&delta)) - return false; - uint32 current = prev + delta; - // TODO(tommi): handle errors - set->push_back(current); - prev = current; + ok = buffer->ReadVarint32(&delta); + if (ok) { + uint32 current = prev + delta; + ok = set->push_back(current); + prev = current; + } } - // TODO(tommi): Handle errors. - return true; + return ok; } // Write a vector as the byte representation of the contents. // // (This only really makes sense for a type T that has sizeof(T)==1, otherwise -// serialized representation is not endian-agnositic. But it is useful to keep +// serialized representation is not endian-agnostic. But it is useful to keep // the possibility of a greater size for experiments comparing Varint32 encoding // of a vector of larger integrals vs a plain form.) // -template<typename T, typename A> -CheckBool WriteVectorU8(const std::vector<T, A>& items, SinkStream* buffer) { +template<typename V> +CheckBool WriteVectorU8(const V& items, SinkStream* buffer) { size_t count = items.size(); bool ok = buffer->WriteSizeVarint32(count); if (count != 0 && ok) { - size_t byte_count = count * sizeof(T); + size_t byte_count = count * sizeof(typename V::value_type); ok = buffer->Write(static_cast<const void*>(&items[0]), byte_count); } return ok; } -template<typename T, typename A> -bool ReadVectorU8(std::vector<T, A>* items, SourceStream* buffer) { +template<typename V> +bool ReadVectorU8(V* items, SourceStream* buffer) { uint32 count; if (!buffer->ReadVarint32(&count)) return false; items->clear(); - // TODO(tommi): check error - items->resize(count); - if (count != 0) { - size_t byte_count = count * sizeof(T); + bool ok = items->resize(count, 0); + if (ok && count != 0) { + size_t byte_count = count * sizeof(typename V::value_type); return buffer->Read(static_cast<void*>(&((*items)[0])), byte_count); } - return true; + return ok; } //////////////////////////////////////////////////////////////////////////////// @@ -161,16 +157,17 @@ static const RVA kUnassignedRVA = static_cast<RVA>(-1); CheckBool EncodedProgram::DefineLabelCommon(RvaVector* rvas, int index, RVA rva) { - if (static_cast<int>(rvas->size()) <= index) { - // TODO(tommi): handle error - rvas->resize(index + 1, kUnassignedRVA); - } - if ((*rvas)[index] != kUnassignedRVA) { - NOTREACHED() << "DefineLabel double assigned " << index; + bool ok = true; + if (static_cast<int>(rvas->size()) <= index) + ok = rvas->resize(index + 1, kUnassignedRVA); + + if (ok) { + DCHECK_EQ((*rvas)[index], kUnassignedRVA) + << "DefineLabel double assigned " << index; + (*rvas)[index] = rva; } - (*rvas)[index] = rva; - // TODO(tommi): Handle errors - return true; + + return ok; } void EncodedProgram::EndLabels() { @@ -194,16 +191,14 @@ void EncodedProgram::FinishLabelsCommon(RvaVector* rvas) { } CheckBool EncodedProgram::AddOrigin(RVA origin) { - //TODO(tommi): Handle errors - ops_.push_back(ORIGIN); - origins_.push_back(origin); - return true; + return ops_.push_back(ORIGIN) && origins_.push_back(origin); } CheckBool EncodedProgram::AddCopy(uint32 count, const void* bytes) { - //TODO(tommi): Handle errors const uint8* source = static_cast<const uint8*>(bytes); + bool ok = true; + // Fold adjacent COPY instructions into one. This nearly halves the size of // an EncodedProgram with only COPY1 instructions since there are approx plain // 16 bytes per reloc. This has a working-set benefit during decompression. @@ -213,49 +208,41 @@ CheckBool EncodedProgram::AddCopy(uint32 count, const void* bytes) { if (!ops_.empty()) { if (ops_.back() == COPY1) { ops_.back() = COPY; - copy_counts_.push_back(1); + ok = copy_counts_.push_back(1); } - if (ops_.back() == COPY) { + if (ok && ops_.back() == COPY) { copy_counts_.back() += count; - for (uint32 i = 0; i < count; ++i) { - copy_bytes_.push_back(source[i]); + for (uint32 i = 0; ok && i < count; ++i) { + ok = copy_bytes_.push_back(source[i]); } - return true; + return ok; } } - if (count == 1) { - ops_.push_back(COPY1); - copy_bytes_.push_back(source[0]); - } else { - ops_.push_back(COPY); - copy_counts_.push_back(count); - for (uint32 i = 0; i < count; ++i) { - copy_bytes_.push_back(source[i]); + if (ok) { + if (count == 1) { + ok = ops_.push_back(COPY1) && copy_bytes_.push_back(source[0]); + } else { + ok = ops_.push_back(COPY) && copy_counts_.push_back(count); + for (uint32 i = 0; ok && i < count; ++i) { + ok = copy_bytes_.push_back(source[i]); + } } } - return true; + return ok; } CheckBool EncodedProgram::AddAbs32(int label_index) { - //TODO(tommi): Handle errors - ops_.push_back(ABS32); - abs32_ix_.push_back(label_index); - return true; + return ops_.push_back(ABS32) && abs32_ix_.push_back(label_index); } CheckBool EncodedProgram::AddRel32(int label_index) { - //TODO(tommi): Handle errors - ops_.push_back(REL32); - rel32_ix_.push_back(label_index); - return true; + return ops_.push_back(REL32) && rel32_ix_.push_back(label_index); } CheckBool EncodedProgram::AddMakeRelocs() { - //TODO(tommi): Handle errors - ops_.push_back(MAKE_BASE_RELOCATION_TABLE); - return true; + return ops_.push_back(MAKE_BASE_RELOCATION_TABLE); } void EncodedProgram::DebuggingSummary() { @@ -393,8 +380,8 @@ bool EncodedProgram::ReadFrom(SourceStreamSet* streams) { // Safe, non-throwing version of std::vector::at(). Returns 'true' for success, // 'false' for out-of-bounds index error. -template<typename T, typename A> -bool VectorAt(const std::vector<T, A>& v, size_t index, T* output) { +template<typename V, typename T> +bool VectorAt(const V& v, size_t index, T* output) { if (index >= v.size()) return false; *output = v[index]; @@ -485,8 +472,7 @@ CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) { if (!VectorAt(abs32_rva_, index, &rva)) return false; uint32 abs32 = static_cast<uint32>(rva + image_base_); - abs32_relocs_.push_back(current_rva); - if (!output->Write(&abs32, 4)) + if (!abs32_relocs_.push_back(current_rva) || !output->Write(&abs32, 4)) return false; current_rva += 4; break; @@ -557,7 +543,7 @@ class RelocBlock { pod.block_size += 2; } - CheckBool Flush(SinkStream* buffer) { + CheckBool Flush(SinkStream* buffer) WARN_UNUSED_RESULT { bool ok = true; if (pod.block_size != 8) { if (pod.block_size % 4 != 0) { // Pad to make size multiple of 4 bytes. diff --git a/courgette/encoded_program.h b/courgette/encoded_program.h index 6d2f440..5acfeb6 100644 --- a/courgette/encoded_program.h +++ b/courgette/encoded_program.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -32,19 +32,21 @@ class EncodedProgram { void set_image_base(uint64 base) { image_base_ = base; } // (2) Address tables and indexes defined first. - CheckBool DefineRel32Label(int index, RVA address); - CheckBool DefineAbs32Label(int index, RVA address); + CheckBool DefineRel32Label(int index, RVA address) WARN_UNUSED_RESULT; + CheckBool DefineAbs32Label(int index, RVA address) WARN_UNUSED_RESULT; void EndLabels(); // (3) Add instructions in the order needed to generate bytes of file. - CheckBool AddOrigin(RVA rva); - CheckBool AddCopy(uint32 count, const void* bytes); - CheckBool AddRel32(int label_index); - CheckBool AddAbs32(int label_index); - CheckBool AddMakeRelocs(); + // NOTE: If any of these methods ever fail, the EncodedProgram instance + // has failed and should be discarded. + CheckBool AddOrigin(RVA rva) WARN_UNUSED_RESULT; + CheckBool AddCopy(uint32 count, const void* bytes) WARN_UNUSED_RESULT; + CheckBool AddRel32(int label_index) WARN_UNUSED_RESULT; + CheckBool AddAbs32(int label_index) WARN_UNUSED_RESULT; + CheckBool AddMakeRelocs() WARN_UNUSED_RESULT; // (3) Serialize binary assembly language tables to a set of streams. - CheckBool WriteTo(SinkStreamSet* streams); + CheckBool WriteTo(SinkStreamSet* streams) WARN_UNUSED_RESULT; // Using an EncodedProgram to generate a byte stream: // @@ -52,7 +54,7 @@ class EncodedProgram { bool ReadFrom(SourceStreamSet* streams); // (5) Assembles the 'binary assembly language' into final file. - CheckBool AssembleTo(SinkStream* buffer); + CheckBool AssembleTo(SinkStream* buffer) WARN_UNUSED_RESULT; private: // Binary assembly language operations. @@ -68,14 +70,14 @@ class EncodedProgram { OP_LAST }; - typedef std::vector<RVA, MemoryAllocator<RVA> > RvaVector; - typedef std::vector<uint32, MemoryAllocator<uint32> > UInt32Vector; - typedef std::vector<uint8, MemoryAllocator<uint8> > UInt8Vector; - typedef std::vector<OP, MemoryAllocator<OP> > OPVector; + typedef NoThrowBuffer<RVA> RvaVector; + typedef NoThrowBuffer<uint32> UInt32Vector; + typedef NoThrowBuffer<uint8> UInt8Vector; + typedef NoThrowBuffer<OP> OPVector; void DebuggingSummary(); - CheckBool GenerateBaseRelocations(SinkStream *buffer); - CheckBool DefineLabelCommon(RvaVector*, int, RVA); + CheckBool GenerateBaseRelocations(SinkStream *buffer) WARN_UNUSED_RESULT; + CheckBool DefineLabelCommon(RvaVector*, int, RVA) WARN_UNUSED_RESULT; void FinishLabelsCommon(RvaVector* addresses); // Binary assembly language tables. diff --git a/courgette/ensemble_apply.cc b/courgette/ensemble_apply.cc index 9621f30..6efbc40 100644 --- a/courgette/ensemble_apply.cc +++ b/courgette/ensemble_apply.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -396,6 +396,8 @@ Status ApplyEnsemblePatch(const FilePath::CharType* old_file_name, SinkStream new_sink_stream; status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream, &new_sink_stream); + if (status != C_OK) + return status; // Write the patched data to |new_file_name|. FilePath new_file_path(new_file_name); diff --git a/courgette/ensemble_create.cc b/courgette/ensemble_create.cc index b70621a..4e285e4 100644 --- a/courgette/ensemble_create.cc +++ b/courgette/ensemble_create.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -233,11 +233,13 @@ Status GenerateEnsemblePatch(SourceStream* base, SinkStream* ensemble_correction = patch_streams.stream(3); size_t number_of_transformations = generators.size(); - tranformation_descriptions->WriteSizeVarint32(number_of_transformations); + if (!tranformation_descriptions->WriteSizeVarint32(number_of_transformations)) + return C_STREAM_ERROR; for (size_t i = 0; i < number_of_transformations; ++i) { CourgettePatchFile::TransformationMethodId kind = generators[i]->Kind(); - tranformation_descriptions->WriteVarint32(kind); + if (!tranformation_descriptions->WriteVarint32(kind)) + return C_STREAM_ERROR; } for (size_t i = 0; i < number_of_transformations; ++i) { @@ -401,17 +403,16 @@ Status GenerateEnsemblePatch(SourceStream* base, // // Final output stream has a header followed by a StreamSet. // - final_patch->WriteVarint32(CourgettePatchFile::kMagic); - final_patch->WriteVarint32(CourgettePatchFile::kVersion); - - final_patch->WriteVarint32( - CalculateCrc(old_region.start(), old_region.length())); - final_patch->WriteVarint32( - CalculateCrc(new_region.start(), new_region.length())); - final_patch->WriteSizeVarint32(final_patch_input_size); - - if (!patch_streams.CopyTo(final_patch)) + if (!final_patch->WriteVarint32(CourgettePatchFile::kMagic) || + !final_patch->WriteVarint32(CourgettePatchFile::kVersion) || + !final_patch->WriteVarint32(CalculateCrc(old_region.start(), + old_region.length())) || + !final_patch->WriteVarint32(CalculateCrc(new_region.start(), + new_region.length())) || + !final_patch->WriteSizeVarint32(final_patch_input_size) || + !patch_streams.CopyTo(final_patch)) { return C_STREAM_ERROR; + } VLOG(1) << "done GenerateEnsemblePatch " << (base::Time::Now() - start_time).InSecondsF() << "s"; diff --git a/courgette/memory_allocator.cc b/courgette/memory_allocator.cc index d45d053..f2aed22 100644 --- a/courgette/memory_allocator.cc +++ b/courgette/memory_allocator.cc @@ -11,46 +11,30 @@ #ifdef OS_WIN -// A helper function to help diagnose failures we've seen in the field. -// The function constructs a string containing the error and throws a runtime -// exception. The calling convention is set to stdcall to force argument -// passing via the stack. -__declspec(noinline) -void __stdcall RuntimeError(DWORD err) { - char buffer[20] = {0}; - wsprintfA(buffer, "err: %u", err); - throw buffer; -} - namespace courgette { // TempFile -TempFile::TempFile() : file_(base::kInvalidPlatformFileValue), size_(0) { +TempFile::TempFile() : file_(base::kInvalidPlatformFileValue) { } TempFile::~TempFile() { Close(); } -FilePath TempFile::PrepareTempFile() { - FilePath path; - if (!file_util::CreateTemporaryFile(&path)) - RuntimeError(::GetLastError()); - return path; -} - void TempFile::Close() { if (valid()) { base::ClosePlatformFile(file_); file_ = base::kInvalidPlatformFileValue; - size_ = 0; } } -void TempFile::Create() { +bool TempFile::Create() { DCHECK(file_ == base::kInvalidPlatformFileValue); - FilePath path(PrepareTempFile()); + FilePath path; + if (!file_util::CreateTemporaryFile(&path)) + return false; + bool created = false; base::PlatformFileError error_code = base::PLATFORM_FILE_OK; int flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ | @@ -59,7 +43,9 @@ void TempFile::Create() { base::PLATFORM_FILE_TEMPORARY; file_ = base::CreatePlatformFile(path, flags, &created, &error_code); if (file_ == base::kInvalidPlatformFileValue) - RuntimeError(error_code); + return false; + + return true; } bool TempFile::valid() const { @@ -70,15 +56,8 @@ base::PlatformFile TempFile::handle() const { return file_; } -size_t TempFile::size() const { - return size_; -} - -void TempFile::SetSize(size_t size) { - bool set = base::TruncatePlatformFile(file_, size); - if (!set) - RuntimeError(::GetLastError()); - size_ = size; +bool TempFile::SetSize(size_t size) { + return base::TruncatePlatformFile(file_, size); } // FileMapping @@ -90,22 +69,25 @@ FileMapping::~FileMapping() { Close(); } -void FileMapping::InitializeView(size_t size) { +bool FileMapping::InitializeView(size_t size) { DCHECK(view_ == NULL); DCHECK(mapping_ != NULL); view_ = ::MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, size); - if (!view_) - RuntimeError(::GetLastError()); + if (!view_) { + Close(); + return false; + } + return true; } -void FileMapping::Create(HANDLE file, size_t size) { +bool FileMapping::Create(HANDLE file, size_t size) { DCHECK(file != INVALID_HANDLE_VALUE); DCHECK(!valid()); mapping_ = ::CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 0, NULL); if (!mapping_) - RuntimeError(::GetLastError()); + return false; - InitializeView(size); + return InitializeView(size); } void FileMapping::Close() { @@ -133,17 +115,22 @@ TempMapping::TempMapping() { TempMapping::~TempMapping() { } -void TempMapping::Initialize(size_t size) { +bool TempMapping::Initialize(size_t size) { // TODO(tommi): The assumption here is that the alignment of pointers (this) // is as strict or stricter than the alignment of the element type. This is // not always true, e.g. __m128 has 16-byte alignment. size += sizeof(this); - file_.Create(); - file_.SetSize(size); - mapping_.Create(file_.handle(), size); + if (!file_.Create() || + !file_.SetSize(size) || + !mapping_.Create(file_.handle(), size)) { + file_.Close(); + return false; + } TempMapping** write = reinterpret_cast<TempMapping**>(mapping_.view()); write[0] = this; + + return true; } void* TempMapping::memory() const { @@ -154,6 +141,10 @@ void* TempMapping::memory() const { return mem; } +bool TempMapping::valid() const { + return mapping_.valid(); +} + // static TempMapping* TempMapping::GetMappingFromPtr(void* mem) { TempMapping* ret = NULL; diff --git a/courgette/memory_allocator.h b/courgette/memory_allocator.h index 4774b88..08defe4 100644 --- a/courgette/memory_allocator.h +++ b/courgette/memory_allocator.h @@ -66,9 +66,9 @@ class TempFile { TempFile(); ~TempFile(); - __declspec(noinline) void Create(); + bool Create(); void Close(); - __declspec(noinline) void SetSize(size_t size); + bool SetSize(size_t size); // Returns true iff the temp file is currently open. bool valid() const; @@ -77,15 +77,8 @@ class TempFile { // a temp file has not been created. base::PlatformFile handle() const; - // Returns the size of the temp file. If the temp file doesn't exist, - // the return value is 0. - size_t size() const; - protected: - __declspec(noinline) FilePath PrepareTempFile(); - base::PlatformFile file_; - size_t size_; }; // Manages a read/write virtual mapping of a physical file. @@ -95,7 +88,7 @@ class FileMapping { ~FileMapping(); // Map a file from beginning to |size|. - __declspec(noinline) void Create(HANDLE file, size_t size); + bool Create(HANDLE file, size_t size); void Close(); // Returns true iff a mapping has been created. @@ -106,7 +99,7 @@ class FileMapping { void* view() const; protected: - __declspec(noinline) void InitializeView(size_t size); + bool InitializeView(size_t size); HANDLE mapping_; void* view_; @@ -122,12 +115,15 @@ class TempMapping { ~TempMapping(); // Creates a temporary file of size |size| and maps it into the current - // process' address space. - __declspec(noinline) void Initialize(size_t size); + // process's address space. + bool Initialize(size_t size); // Returns a writable pointer to the reserved memory. void* memory() const; + // Returns true if the mapping is valid and memory is available. + bool valid() const; + // Returns a pointer to the TempMapping instance that allocated the |mem| // block of memory. It's the callers responsibility to make sure that // the memory block was allocated by the TempMapping class. @@ -138,10 +134,11 @@ class TempMapping { FileMapping mapping_; }; -// An STL compatible memory allocator class that allocates memory either -// from the heap or via a temporary file. A file allocation will be made -// if either the requested memory size exceeds |kMaxHeapAllocationSize| -// or if a heap allocation fails. +// A memory allocator class that allocates memory either from the heap or via a +// temporary file. The interface is STL inspired but the class does not throw +// STL exceptions on allocation failure. Instead it returns NULL. +// A file allocation will be made if either the requested memory size exceeds +// |kMaxHeapAllocationSize| or if a heap allocation fails. // Allocating the memory as a mapping of a temporary file solves the problem // that there might not be enough physical memory and pagefile to support the // allocation. This can happen because these resources are too small, or @@ -174,7 +171,7 @@ class MemoryAllocator { template<class OtherT> struct rebind { - // convert an MemoryAllocator<T> to a MemoryAllocator<OtherT> + // convert a MemoryAllocator<T> to a MemoryAllocator<OtherT> typedef MemoryAllocator<OtherT> other; }; @@ -183,11 +180,11 @@ class MemoryAllocator { // We can't use an explicit constructor here, as dictated by our style guide. // The implementation of basic_string in Visual Studio 2010 prevents this. - MemoryAllocator(const MemoryAllocator<T>& other) _THROW0() { + MemoryAllocator(const MemoryAllocator<T>& other) _THROW0() { // NOLINT } template<class OtherT> - explicit MemoryAllocator(const MemoryAllocator<OtherT>& other) _THROW0() { + MemoryAllocator(const MemoryAllocator<OtherT>& other) _THROW0() { // NOLINT } ~MemoryAllocator() { @@ -213,7 +210,7 @@ class MemoryAllocator { count++; if (count > max_size()) - throw std::length_error("overflow"); + return NULL; size_type bytes = count * sizeof(T); uint8* mem = NULL; @@ -226,12 +223,13 @@ class MemoryAllocator { } 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 TempMapping(); - mapping->Initialize(bytes); - mem = reinterpret_cast<uint8*>(mapping->memory()); - mem[0] = static_cast<uint8>(FILE_ALLOCATION); + TempMapping* mapping = new(std::nothrow) TempMapping(); + if (mapping && mapping->Initialize(bytes)) { + mem = reinterpret_cast<uint8*>(mapping->memory()); + mem[0] = static_cast<uint8>(FILE_ALLOCATION); + } } - return reinterpret_cast<pointer>(mem + sizeof(T)); + return mem ? reinterpret_cast<pointer>(mem + sizeof(T)) : NULL; } pointer allocate(size_type count, const void* hint) { @@ -246,7 +244,7 @@ class MemoryAllocator { ptr->~T(); } - size_t max_size() const _THROW0() { + size_type max_size() const _THROW0() { size_type count = static_cast<size_type>(-1) / sizeof(T); return (0 < count ? count : 1); } @@ -254,14 +252,239 @@ class MemoryAllocator { #else // OS_WIN -// On Mac, Linux, we just use the default STL allocator. +// On Mac, Linux, we use a bare bones implementation that only does +// heap allocations. template<class T> -class MemoryAllocator : public std::allocator<T> { +class MemoryAllocator { public: + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type* const_pointer; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + template<class OtherT> + struct rebind { + // convert a MemoryAllocator<T> to a MemoryAllocator<OtherT> + typedef MemoryAllocator<OtherT> other; + }; + + MemoryAllocator() { + } + + explicit MemoryAllocator(const MemoryAllocator<T>& other) { + } + + template<class OtherT> + explicit MemoryAllocator(const MemoryAllocator<OtherT>& other) { + } + + ~MemoryAllocator() { + } + + void deallocate(pointer ptr, size_type size) { + delete [] ptr; + } + + pointer allocate(size_type count) { + if (count > max_size()) + return NULL; + return reinterpret_cast<pointer>( + new(std::nothrow) uint8[count * sizeof(T)]); + } + + pointer allocate(size_type count, const void* hint) { + return allocate(count); + } + + void construct(pointer ptr, const T& value) { + ::new(ptr) T(value); + } + + void destroy(pointer ptr) { + ptr->~T(); + } + + size_type max_size() const { + size_type count = static_cast<size_type>(-1) / sizeof(T); + return (0 < count ? count : 1); + } }; #endif // OS_WIN +// Manages a growable buffer. The buffer allocation is done by the +// MemoryAllocator class. This class will not throw exceptions so call sites +// must be prepared to handle memory allocation failures. +// The interface is STL inspired to avoid having to make too many changes +// to code that previously was using STL. +template<typename T, class Allocator = MemoryAllocator<T> > +class NoThrowBuffer { + public: + typedef T value_type; + static const size_t kAllocationFailure = 0xffffffff; + static const size_t kStartSize = sizeof(T) > 0x100 ? 1 : 0x100 / sizeof(T); + + NoThrowBuffer() : buffer_(NULL), size_(0), alloc_size_(0) { + } + + ~NoThrowBuffer() { + clear(); + } + + void clear() { + if (buffer_) { + alloc_.deallocate(buffer_, alloc_size_); + buffer_ = NULL; + size_ = 0; + alloc_size_ = 0; + } + } + + bool empty() const { + return size_ == 0; + } + + CheckBool reserve(size_t size) WARN_UNUSED_RESULT { + if (failed()) + return false; + + if (size <= alloc_size_) + return true; + + if (size < kStartSize) + size = kStartSize; + + T* new_buffer = alloc_.allocate(size); + if (!new_buffer) { + clear(); + alloc_size_ = kAllocationFailure; + } else { + if (buffer_) { + memcpy(new_buffer, buffer_, size_ * sizeof(T)); + alloc_.deallocate(buffer_, alloc_size_); + } + buffer_ = new_buffer; + alloc_size_ = size; + } + + return !failed(); + } + + CheckBool append(const T* data, size_t size) WARN_UNUSED_RESULT { + if (failed()) + return false; + + if (size > alloc_.max_size() - size_) + return false; + + if (!size) + return true; + + if ((alloc_size_ - size_) < size) { + const size_t max_size = alloc_.max_size(); + size_t new_size = alloc_size_ ? alloc_size_ : kStartSize; + while (new_size < size_ + size) { + if (new_size < max_size - new_size) { + new_size *= 2; + } else { + new_size = max_size; + } + } + if (!reserve(new_size)) + return false; + } + + memcpy(buffer_ + size_, data, size * sizeof(T)); + size_ += size; + + return true; + } + + CheckBool resize(size_t size, const T& init_value) WARN_UNUSED_RESULT { + if (size > size_) { + if (!reserve(size)) + return false; + for (size_t i = size_; i < size; ++i) + buffer_[i] = init_value; + } else if (size < size_) { + // TODO(tommi): Should we allocate a new, smaller buffer? + // It might be faster for us to simply change the size. + } + + size_ = size; + + return true; + } + + CheckBool push_back(const T& item) WARN_UNUSED_RESULT { + return append(&item, 1); + } + + const T& back() const { + return buffer_[size_ - 1]; + } + + T& back() { + return buffer_[size_ - 1]; + } + + const T* begin() const { + if (!size_) + return NULL; + return &buffer_[0]; + } + + T* begin() { + if (!size_) + return NULL; + return &buffer_[0]; + } + + const T* end() const { + if (!size_) + return NULL; + return &buffer_[size_ - 1]; + } + + T* end() { + if (!size_) + return NULL; + return &buffer_[size_ - 1]; + } + + const T& operator[](size_t index) const { + DCHECK(index < size_); + return buffer_[index]; + } + + T& operator[](size_t index) { + DCHECK(index < size_); + return buffer_[index]; + } + + size_t size() const { + return size_; + } + + T* data() const { + return buffer_; + } + + // Returns true if an allocation failure has ever occurred for this object. + bool failed() const { + return alloc_size_ == kAllocationFailure; + } + + protected: + T* buffer_; + size_t size_; // how much of the buffer we're using. + size_t alloc_size_; // how much space we have allocated. + Allocator alloc_; +}; + } // namespace courgette #endif // COURGETTE_MEMORY_ALLOCATOR_H_ diff --git a/courgette/streams.cc b/courgette/streams.cc index ef81ded..df769b1 100644 --- a/courgette/streams.cc +++ b/courgette/streams.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -182,9 +182,7 @@ bool SourceStream::Skip(size_t byte_count) { } CheckBool SinkStream::Write(const void* data, size_t byte_count) { - buffer_.append(static_cast<const char*>(data), byte_count); - //TODO(tommi): return error on failure. - return true; + return buffer_.append(static_cast<const char*>(data), byte_count); } CheckBool SinkStream::WriteVarint32(uint32 value) { @@ -214,7 +212,7 @@ CheckBool SinkStream::WriteSizeVarint32(size_t value) { } CheckBool SinkStream::Append(SinkStream* other) { - bool ret = Write(other->buffer_.c_str(), other->buffer_.size()); + bool ret = Write(other->buffer_.data(), other->buffer_.size()); if (ret) other->Retire(); return ret; @@ -222,7 +220,6 @@ CheckBool SinkStream::Append(SinkStream* other) { void SinkStream::Retire() { buffer_.clear(); - buffer_.reserve(0); // Non-binding request to reduce storage. } //////////////////////////////////////////////////////////////////////////////// diff --git a/courgette/streams.h b/courgette/streams.h index 2543e99..ff65d13 100644 --- a/courgette/streams.h +++ b/courgette/streams.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -121,21 +121,21 @@ class SinkStream { ~SinkStream() {} // Appends |byte_count| bytes from |data| to the stream. - CheckBool Write(const void* data, size_t byte_count); + CheckBool Write(const void* data, size_t byte_count) WARN_UNUSED_RESULT; // Appends the 'varint32' encoding of |value| to the stream. - CheckBool WriteVarint32(uint32 value); + CheckBool WriteVarint32(uint32 value) WARN_UNUSED_RESULT; // Appends the 'varint32' encoding of |value| to the stream. - CheckBool WriteVarint32Signed(int32 value); + CheckBool WriteVarint32Signed(int32 value) WARN_UNUSED_RESULT; // Appends the 'varint32' encoding of |value| to the stream. // On platforms where sizeof(size_t) != sizeof(int32), do a safety check. - CheckBool WriteSizeVarint32(size_t value); + CheckBool WriteSizeVarint32(size_t value) WARN_UNUSED_RESULT; // Contents of |other| are appended to |this| stream. The |other| stream // becomes retired. - CheckBool Append(SinkStream* other); + CheckBool Append(SinkStream* other) WARN_UNUSED_RESULT; // Returns the number of bytes in this SinkStream size_t Length() const { return buffer_.size(); } @@ -144,26 +144,20 @@ class SinkStream { // Writing to the stream invalidates the pointer. The SinkStream continues to // own the memory. const uint8* Buffer() const { - return reinterpret_cast<const uint8*>(buffer_.c_str()); + return reinterpret_cast<const uint8*>(buffer_.data()); } // Hints that the stream will grow by an additional |length| bytes. // Caller must be prepared to handle memory allocation problems. - CheckBool Reserve(size_t length) { - buffer_.reserve(length + buffer_.length()); - //TODO(tommi): return false when allocation fails. - return true; + CheckBool Reserve(size_t length) WARN_UNUSED_RESULT { + return buffer_.reserve(length + buffer_.size()); } // Finished with this stream and any storage it has. void Retire(); private: - // Use a string to manage the stream's memory. - typedef std::basic_string<char, - std::char_traits<char>, - MemoryAllocator<char> > SinkBuffer; - SinkBuffer buffer_; + NoThrowBuffer<char> buffer_; DISALLOW_COPY_AND_ASSIGN(SinkStream); }; @@ -222,15 +216,15 @@ class SinkStreamSet { // CopyTo serializes the streams in this SinkStreamSet into a single target // stream. The serialized format may be re-read by initializing a // SourceStreamSet with a buffer containing the data. - CheckBool CopyTo(SinkStream* combined_stream); + CheckBool CopyTo(SinkStream* combined_stream) WARN_UNUSED_RESULT; // Writes the streams of |set| into the corresponding streams of |this|. // Stream zero first has some metadata written to it. |set| becomes retired. // Partner to SourceStreamSet::ReadSet. - CheckBool WriteSet(SinkStreamSet* set); + CheckBool WriteSet(SinkStreamSet* set) WARN_UNUSED_RESULT; private: - CheckBool CopyHeaderTo(SinkStream* stream); + CheckBool CopyHeaderTo(SinkStream* stream) WARN_UNUSED_RESULT; size_t count_; SinkStream streams_[kMaxStreams]; diff --git a/courgette/win32_x86_generator.h b/courgette/win32_x86_generator.h index 8edb143..496a2ce 100644 --- a/courgette/win32_x86_generator.h +++ b/courgette/win32_x86_generator.h @@ -27,8 +27,11 @@ class CourgetteWin32X86PatchGenerator : public TransformationPatchGenerator { } Status WriteInitialParameters(SinkStream* parameter_stream) { - parameter_stream->WriteSizeVarint32(old_element_->offset_in_ensemble()); - parameter_stream->WriteSizeVarint32(old_element_->region().length()); + if (!parameter_stream->WriteSizeVarint32( + old_element_->offset_in_ensemble()) || + !parameter_stream->WriteSizeVarint32(old_element_->region().length())) { + return C_STREAM_ERROR; + } return C_OK; // TODO(sra): Initialize |patcher_| with these parameters. } diff --git a/courgette/win32_x86_patcher.h b/courgette/win32_x86_patcher.h index 9ab53d9..6b85021 100644 --- a/courgette/win32_x86_patcher.h +++ b/courgette/win32_x86_patcher.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -60,8 +60,6 @@ class CourgetteWin32X86Patcher : public TransformationPatcher { status = WriteEncodedProgram(encoded, transformed_element); DeleteEncodedProgram(encoded); - if (status != C_OK) - return status; return status; } |