summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 17:42:45 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-06 17:42:45 +0000
commit43a9e24a52fa867db98fc2195b8db85b4729e7a1 (patch)
treecad7a14c415542083ac3d1ecc2df1fd86f789557
parent6768ac0b06ae36ec7b2d27adfb9b64fc17f57cee (diff)
downloadchromium_src-43a9e24a52fa867db98fc2195b8db85b4729e7a1.zip
chromium_src-43a9e24a52fa867db98fc2195b8db85b4729e7a1.tar.gz
chromium_src-43a9e24a52fa867db98fc2195b8db85b4729e7a1.tar.bz2
Switch out use of std::string and std::vector for large allocations for a buffer class that doesn't throw exceptions.
The new buffer class is pretty simple and relies on the MemoryAllocator class that I previously to back large allocations with mapped files when memory is scarce. That reduced the number of crashes quite a bit but we still crash on machines that are simply out of diskspace as well. So, the right thing to do is to expect and handle failures which is what this cl is all about. What we should see once this has landed is that crash dumps due to courgette running out of disk space should disappear from crash/ and instead we should see the number of users that run into this particular problem in dashboards. TEST=Courgette out-of-memory/out-of-diskspace errors should disappear from crash/ BUG=74777 Review URL: http://codereview.chromium.org/6677141 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80648 0039d316-1c4b-4281-b951-d872f2087c98
-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;
}