Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(511)

Unified Diff: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp

Issue 1139673004: Harden writer of munged bitcode for fuzzing (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Fix issues in last patch. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeUtils.cpp ('k') | unittests/Bitcode/CMakeLists.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp
diff --git a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp
index d036c15c53848c3c674eaa18ebf7da6078a2340b..b536fe3c848a4d81241cb4b7f6e39c49313451de 100644
--- a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp
+++ b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp
@@ -14,35 +14,58 @@
#include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
-// For debugging. When true, shows each PNaCl record that is
-// emitted to the bitcode file.
-static bool DebugEmitRecord = false;
+// For debugging. When true, shows trace information of emitting
+// bitcode.
+static bool DebugEmit = false;
+
+// Description of current block scope
+struct BlockScope {
+ BlockScope(unsigned CurBlockID, size_t AbbrevIndexLimit)
+ : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit) {}
+ unsigned CurBlockID;
+ // Defines the maximum value for abbreviation indices in block.
+ size_t AbbrevIndexLimit;
+ void print(raw_ostream &Out) const {
+ Out << "BlockScope(ID=" << CurBlockID << ", AbbrevIndexLimit="
+ << AbbrevIndexLimit << ")";
+ }
+};
+
+inline raw_ostream &operator<<(raw_ostream &Out, const BlockScope &Scope) {
+ Scope.print(Out);
+ return Out;
+}
// State of bitcode writing.
struct WriteState {
- // The block ID associated with the block being written.
- int WriteBlockID = -1;
+ // The block ID associated with records not in any block.
+ static const unsigned UnknownWriteBlockID = UINT_MAX;
// The SetBID for the blockinfo block.
- int SetBID = -1;
- // The stack of maximum abbreviation indices allowed by block enter record.
- SmallVector<uint64_t, 3> AbbrevIndexLimitStack;
+ unsigned SetBID = UnknownWriteBlockID;
+ // The stack of scopes the writer is in.
+ SmallVector<BlockScope, 3> ScopeStack;
// The set of write flags to use.
const NaClMungedBitcode::WriteFlags &Flags;
// The results of the attempted write.
NaClMungedBitcode::WriteResults Results;
+ // The minimum number of bits allowed to be specified in a block.
+ const unsigned BlockMinBits;
- WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {}
+ WriteState(const NaClMungedBitcode::WriteFlags &Flags)
+ : Flags(Flags),
+ BlockMinBits(NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV)) {
+ BlockScope Scope(UnknownWriteBlockID, naclbitc::DEFAULT_MAX_ABBREV);
+ ScopeStack.push_back(Scope);
+ }
// Returns stream to print error message to.
- raw_ostream &Error() {
- ++Results.NumErrors;
- return Flags.getErrStream() << "Error (Block " << WriteBlockID << "): ";
- }
+ raw_ostream &Error();
// Returns stream to print error message to, assuming that
// the error message can be repaired if Flags.TryToRecover is true.
@@ -52,28 +75,142 @@ struct WriteState {
return Error();
}
+ bool atOutermostScope() {
+ assert(!ScopeStack.empty());
+ return ScopeStack.size() == 1;
+ }
+
+ unsigned getCurWriteBlockID() const {
+ assert(!ScopeStack.empty());
+ return ScopeStack.back().CurBlockID;
+ }
+
+ unsigned getCurAbbrevIndexLimit() const {
+ assert(!ScopeStack.empty());
+ return ScopeStack.back().AbbrevIndexLimit;
+ }
+
// Converts the abbreviation record to the corresponding abbreviation.
// Returns nullptr if unable to build abbreviation.
NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record);
// Emits the given record to the bitcode file. Returns true if
// successful.
- bool emitRecord(NaClBitstreamWriter &Writer,
- const NaClBitcodeAbbrevRecord &Record);
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT
+ emitRecord(NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record);
- // Adds any missing end blocks to written bitcode.
- void writeMissingEndBlocks(NaClBitstreamWriter &Writer) {
- while (!AbbrevIndexLimitStack.empty()) {
- Writer.ExitBlock();
- AbbrevIndexLimitStack.pop_back();
- }
+ // Enter the given block
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT
+ enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID,
+ uint64_t NumBits, const NaClBitcodeAbbrevRecord &Record);
+
+ // Exit current block and return to previous block. Silently recovers
+ // if at outermost scope.
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT
+ exitBlock(NaClBitstreamWriter &Writer,
+ const NaClBitcodeAbbrevRecord *Record = nullptr) {
+ if (atOutermostScope())
+ return false;
+ Writer.ExitBlock();
+ ScopeStack.pop_back();
+ if (DebugEmit)
+ printScopeStack(errs());
+ return true;
+ }
+
+ // Completes the write.
+ NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer,
+ bool RecoverSilently);
+
+ void printScopeStack(raw_ostream &Out) {
+ Out << "Scope Stack:\n";
+ for (auto &Scope : ScopeStack)
+ Out << " " << Scope << "\n";
}
};
+raw_ostream &WriteState::Error() {
+ ++Results.NumErrors;
+ raw_ostream &ErrStrm = Flags.getErrStream();
+ unsigned WriteBlockID = getCurWriteBlockID();
+ ErrStrm << "Error (Block ";
+ if (WriteBlockID == UnknownWriteBlockID)
+ ErrStrm << "unknown";
+ else
+ ErrStrm << WriteBlockID;
+ return ErrStrm << "): ";
+}
+
+bool WriteState::enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID,
+ uint64_t NumBits,
+ const NaClBitcodeAbbrevRecord &Record) {
+ if (NumBits < BlockMinBits || NumBits > naclbitc::MaxAbbrevWidth) {
+ RecoverableError()
+ << "Block index bit limit " << NumBits << " invalid. Must be in ["
+ << BlockMinBits << ".." << naclbitc::MaxAbbrevWidth << "]: "
+ << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ NumBits = naclbitc::MaxAbbrevWidth;
+ }
+ if (WriteBlockID > UINT_MAX) {
+ RecoverableError() << "Block id must be <= " << UINT_MAX
+ << ": " << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ WriteBlockID = UnknownWriteBlockID;
+ }
+
+ uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1;
+ BlockScope Scope(WriteBlockID, MaxAbbrev);
+ ScopeStack.push_back(Scope);
+ if (DebugEmit)
+ printScopeStack(errs());
+ if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
+ unsigned DefaultMaxBits =
+ NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
+ if (NumBits != DefaultMaxBits) {
+ RecoverableError()
+ << "Numbits entry for abbreviations record not "
+ << DefaultMaxBits << " but found " << NumBits <<
+ ": " << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ }
+ Writer.EnterBlockInfoBlock();
+ } else {
+ NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
+ Writer.EnterSubblock(WriteBlockID, CurCodeLen);
+ }
+ return true;
+}
+
+NaClMungedBitcode::WriteResults &WriteState::finish(
+ NaClBitstreamWriter &Writer, bool RecoverSilently) {
+ // Be sure blocks are balanced.
+ while (!atOutermostScope()) {
+ if (!RecoverSilently)
+ RecoverableError() << "Missing close block.\n";
+ if (!exitBlock(Writer)) {
+ Error() << "Failed to add missing close block at end of file.\n";
+ break;
+ }
+ }
+
+ // Be sure that generated bitcode buffer is word aligned.
+ if (Writer.GetCurrentBitNo() % 4 * CHAR_BIT) {
+ if (!RecoverSilently)
+ RecoverableError() << "Written bitstream not word aligned\n";
+ // Force a repair so that the bitstream writer doesn't crash.
+ Writer.FlushToWord();
+ }
+ return Results;
+}
+
bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
const NaClBitcodeAbbrevRecord &Record) {
size_t NumValues = Record.Values.size();
- if (DebugEmitRecord) {
+ if (DebugEmit) {
errs() << "Emit " << Record.Abbrev << ": <" << Record.Code;
for (size_t i = 0; i < NumValues; ++i) {
errs() << ", " << Record.Values[i];
@@ -83,8 +220,8 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
switch (Record.Code) {
case naclbitc::BLK_CODE_ENTER: {
- unsigned NumBits = NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
- WriteBlockID = -1;
+ uint64_t WriteBlockID = UnknownWriteBlockID;
+ uint64_t NumBits = naclbitc::MaxAbbrevWidth; // Default to safest value.
if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) {
RecoverableError()
<< "Uses illegal abbreviation index in enter block record: "
@@ -92,43 +229,27 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
if (!Flags.getTryToRecover())
return false;
}
- if (NumValues == 2) {
+ if (NumValues != 2) {
+ RecoverableError()
+ << "Values for enter record should be of size 2, but found "
+ << NumValues << ": " << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ }
+ if (NumValues > 0)
WriteBlockID = Record.Values[0];
+ if (NumValues > 1)
NumBits = Record.Values[1];
- if (NumBits > 32 || NumBits < 2) {
- RecoverableError()
- << "Bit size " << NumBits << " for record should be "
- << (NumBits > 32 ? "<= 32" : ">= 2") << ": " << Record << "\n";
- if (!Flags.getTryToRecover())
- return false;
- NumBits = 32;
- }
- } else {
- Error() << "Values for enter record should be of size 2, but found "
- << NumValues << ": " << Record << "\n";
- return false;
- }
- uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1;
- AbbrevIndexLimitStack.push_back(MaxAbbrev);
- if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
- unsigned DefaultMaxBits =
- NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV);
- if (NumBits != DefaultMaxBits) {
- RecoverableError()
- << "Numbits entry for abbreviations record not "
- << DefaultMaxBits << " but found " << NumBits <<
- ": " << Record << "\n";
- if (!Flags.getTryToRecover())
- return false;
- }
- Writer.EnterBlockInfoBlock();
- } else {
- NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev);
- Writer.EnterSubblock(WriteBlockID, CurCodeLen);
- }
- break;
+ return enterBlock(Writer, WriteBlockID, NumBits, Record);
}
- case naclbitc::BLK_CODE_EXIT:
+ case naclbitc::BLK_CODE_EXIT: {
+ if (atOutermostScope()) {
+ RecoverableError()
+ << "Extraneous exit block: " << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ break;
+ }
if (Record.Abbrev != naclbitc::END_BLOCK) {
RecoverableError()
<< "Uses illegal abbreviation index in exit block record: "
@@ -142,10 +263,13 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
if (!Flags.getTryToRecover())
return false;
}
- if (!AbbrevIndexLimitStack.empty())
- AbbrevIndexLimitStack.pop_back();
- Writer.ExitBlock();
+ if (!exitBlock(Writer)) {
+ Error() << "Failed to write exit block, can't continue: "
+ << Record << "\n";
+ return false;
+ }
break;
+ }
case naclbitc::BLK_CODE_DEFINE_ABBREV: {
if (Record.Abbrev != naclbitc::DEFINE_ABBREV) {
RecoverableError()
@@ -154,10 +278,17 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
if (!Flags.getTryToRecover())
return false;
}
+ if (getCurWriteBlockID() != naclbitc::BLOCKINFO_BLOCK_ID
+ && Writer.getMaxCurAbbrevIndex() >= getCurAbbrevIndexLimit()) {
+ RecoverableError() << "Exceeds abbreviation index limit of "
+ << getCurAbbrevIndexLimit() << ": " << Record << "\n";
+ // Recover by not writing.
+ return Flags.getTryToRecover();
+ }
NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record);
if (Abbrev == NULL)
return Flags.getTryToRecover();
- if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) {
+ if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) {
Writer.EmitBlockInfoAbbrev(SetBID, Abbrev);
} else {
Writer.EmitAbbrev(Abbrev);
@@ -170,23 +301,30 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
Writer.Emit(Value, 8);
break;
default:
- if (AbbrevIndexLimitStack.empty()) {
- Error() << "Can't write record outside record block: " << Record << "\n";
- return false;
- }
bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD;
+ if (atOutermostScope()) {
+ RecoverableError() << "Record outside block: " << Record << "\n";
+ if (!Flags.getTryToRecover())
+ return false;
+ // Create a dummy block to hold record.
+ if (!enterBlock(Writer, UnknownWriteBlockID,
+ naclbitc::DEFAULT_MAX_ABBREV, Record)) {
+ Error() << "Failed to recover from record outside block\n";
+ return false;
+ }
+ UsesDefaultAbbrev = true;
+ }
if (!UsesDefaultAbbrev
&& !Writer.isUserRecordAbbreviation(Record.Abbrev)) {
// Illegal abbreviation index found.
if (Flags.getWriteBadAbbrevIndex()) {
Error() << "Uses illegal abbreviation index: " << Record << "\n";
// Generate bad abbreviation index so that the bitcode reader
- // can be tested.
+ // can be tested, and then quit.
Results.WroteBadAbbrevIndex = true;
Writer.EmitCode(Record.Abbrev);
- // Note: We need to close blocks or the bitcode Writer will terminate
- // due to assertions.
- writeMissingEndBlocks(Writer);
+ bool RecoverSilently = true;
+ finish(Writer, RecoverSilently);
return false;
}
RecoverableError() << "Uses illegal abbreviation index: "
@@ -195,7 +333,7 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer,
return false;
UsesDefaultAbbrev = true;
}
- if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID
+ if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID
&& Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) {
// Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev,
// based on the SetBID value. Don't bother to generate SetBID record here.
@@ -322,12 +460,7 @@ NaClMungedBitcode::WriteResults NaClMungedBitcode::writeMaybeRepair(
if (!State.emitRecord(Writer, Record))
break;
}
- if (!State.AbbrevIndexLimitStack.empty()) {
- State.RecoverableError()
- << "Bitcode missing " << State.AbbrevIndexLimitStack.size()
- << " close blocks.\n";
- if (Flags.getTryToRecover())
- State.writeMissingEndBlocks(Writer);
- }
- return State.Results;
+ bool RecoverSilently =
+ State.Results.NumErrors > 0 && !Flags.getTryToRecover();
+ return State.finish(Writer, RecoverSilently);
}
« no previous file with comments | « lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeUtils.cpp ('k') | unittests/Bitcode/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698