summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/installer/setup/setup_main.cc3
-rw-r--r--chrome/installer/setup/setup_util.cc11
-rw-r--r--chrome/installer/util/util_constants.h1
-rw-r--r--courgette/adjustment_method.cc6
-rw-r--r--courgette/adjustment_method_2.cc4
-rw-r--r--courgette/adjustment_method_unittest.cc14
-rw-r--r--courgette/assembly_program.cc60
-rw-r--r--courgette/assembly_program.h26
-rw-r--r--courgette/courgette_tool.cc39
-rw-r--r--courgette/disassembler.cc68
-rw-r--r--courgette/encode_decode_unittest.cc4
-rw-r--r--courgette/encoded_program.cc154
-rw-r--r--courgette/encoded_program.h34
-rw-r--r--courgette/ensemble_apply.cc4
-rw-r--r--courgette/ensemble_create.cc27
-rw-r--r--courgette/memory_allocator.cc75
-rw-r--r--courgette/memory_allocator.h281
-rw-r--r--courgette/streams.cc9
-rw-r--r--courgette/streams.h32
-rw-r--r--courgette/win32_x86_generator.h7
-rw-r--r--courgette/win32_x86_patcher.h4
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;
}