| 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);
|
| }
|
|
|