Index: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
diff --git a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
index b536fe3c848a4d81241cb4b7f6e39c49313451de..da2907b1a9ee44af02ac208e9d5321f59451f7af 100644 |
--- a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
+++ b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
@@ -16,6 +16,8 @@ |
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
#include "llvm/Support/raw_ostream.h" |
+#include <set> |
+ |
using namespace llvm; |
namespace { |
@@ -27,13 +29,19 @@ static bool DebugEmit = false; |
// Description of current block scope |
struct BlockScope { |
BlockScope(unsigned CurBlockID, size_t AbbrevIndexLimit) |
- : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit) {} |
+ : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit), |
+ OmittedAbbreviations(false) {} |
unsigned CurBlockID; |
// Defines the maximum value for abbreviation indices in block. |
size_t AbbrevIndexLimit; |
+ // Defines if an abbreviation definition was omitted (i.e. not |
+ // written) from this block. Used to turn off writing further |
+ // abbreviation definitions for this block. |
+ bool OmittedAbbreviations; |
void print(raw_ostream &Out) const { |
Out << "BlockScope(ID=" << CurBlockID << ", AbbrevIndexLimit=" |
- << AbbrevIndexLimit << ")"; |
+ << AbbrevIndexLimit << "OmittedAbbreviations=" |
+ << OmittedAbbreviations << ")"; |
} |
}; |
@@ -49,13 +57,16 @@ struct WriteState { |
// The SetBID for the blockinfo block. |
unsigned SetBID = UnknownWriteBlockID; |
// The stack of scopes the writer is in. |
- SmallVector<BlockScope, 3> ScopeStack; |
+ SmallVector<BlockScope, 4> 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; |
+ // The set of block IDs for which abbreviation definitions have been |
+ // omitted in the blockinfo block. |
+ std::set<unsigned> BlocksWithOmittedAbbrevs; |
WriteState(const NaClMungedBitcode::WriteFlags &Flags) |
: Flags(Flags), |
@@ -90,6 +101,23 @@ struct WriteState { |
return ScopeStack.back().AbbrevIndexLimit; |
} |
+ // Returns whether any abbreviation definitions were not written to |
+ // the bitcode buffer. |
+ bool curBlockHasOmittedAbbreviations() const { |
+ assert(!ScopeStack.empty()); |
+ return ScopeStack.back().OmittedAbbreviations |
+ || BlocksWithOmittedAbbrevs.count(getCurWriteBlockID()); |
+ } |
+ |
+ // Marks that an abbreviation definition is being omitted (i.e. not |
+ // written) for the current block. |
+ void markCurrentBlockWithOmittedAbbreviations() { |
+ assert(!ScopeStack.empty()); |
+ ScopeStack.back().OmittedAbbreviations = true; |
+ if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) |
+ BlocksWithOmittedAbbrevs.insert(SetBID); |
+ } |
+ |
// Converts the abbreviation record to the corresponding abbreviation. |
// Returns nullptr if unable to build abbreviation. |
NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); |
@@ -97,7 +125,8 @@ struct WriteState { |
// Emits the given record to the bitcode file. Returns true if |
// successful. |
bool LLVM_ATTRIBUTE_UNUSED_RESULT |
- emitRecord(NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record); |
+ emitRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record); |
// Enter the given block |
bool LLVM_ATTRIBUTE_UNUSED_RESULT |
@@ -118,6 +147,21 @@ struct WriteState { |
return true; |
} |
+ void WriteRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record, |
+ bool UsesDefaultAbbrev) { |
+ if (UsesDefaultAbbrev) |
+ Writer.EmitRecord(Record.Code, Record.Values); |
+ else |
+ Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); |
+ } |
+ |
+ // Returns true if the abbreviation index defines an abbreviation |
+ // that can be applied to the record. |
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT |
+ canApplyAbbreviation(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record); |
+ |
// Completes the write. |
NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer, |
bool RecoverSilently); |
@@ -185,6 +229,55 @@ bool WriteState::enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID, |
return true; |
} |
+bool WriteState::canApplyAbbreviation( |
+ NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record) { |
+ const NaClBitCodeAbbrev *Abbrev = Writer.getAbbreviation(Record.Abbrev); |
+ if (Abbrev == nullptr) |
+ return false; |
+ |
+ // Merge record code into values and then match abbreviation. |
+ NaClBitcodeValues Values(Record); |
+ size_t ValueIndex = 0; |
+ size_t ValuesSize = Values.size(); |
+ size_t AbbrevIndex = 0; |
+ size_t AbbrevSize = Abbrev->getNumOperandInfos(); |
+ bool FoundArray = false; |
+ while (ValueIndex < ValuesSize && AbbrevIndex < AbbrevSize) { |
+ const NaClBitCodeAbbrevOp *Op = &Abbrev->getOperandInfo(AbbrevIndex++); |
+ uint64_t Value = Values[ValueIndex++]; |
+ if (Op->getEncoding() == NaClBitCodeAbbrevOp::Array) { |
+ if (AbbrevIndex + 1 != AbbrevSize) |
+ return false; |
+ Op = &Abbrev->getOperandInfo(AbbrevIndex); |
+ --AbbrevIndex; // i.e. don't advance to next abbreviation op. |
+ FoundArray = true; |
+ } |
+ switch (Op->getEncoding()) { |
+ case NaClBitCodeAbbrevOp::Literal: |
+ if (Value != Op->getValue()) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::Fixed: |
+ if (Value >= (static_cast<uint64_t>(1) |
+ << NaClBitstreamWriter::MaxEmitNumBits) |
+ || NaClBitsNeededForValue(Value) > Op->getValue()) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::VBR: |
+ if (Op->getValue() < 2) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::Array: |
+ llvm_unreachable("Array(Array) abbreviation is not legal!"); |
+ case NaClBitCodeAbbrevOp::Char6: |
+ if (!Op->isChar6(Value)) |
+ return false; |
+ continue; |
+ } |
+ } |
+ return ValueIndex == ValuesSize && (FoundArray || AbbrevIndex == AbbrevSize); |
+} |
+ |
NaClMungedBitcode::WriteResults &WriteState::finish( |
NaClBitstreamWriter &Writer, bool RecoverSilently) { |
// Be sure blocks are balanced. |
@@ -271,6 +364,12 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
break; |
} |
case naclbitc::BLK_CODE_DEFINE_ABBREV: { |
+ if (curBlockHasOmittedAbbreviations()) { |
+ // If reached, a previous abbreviation for the block was omitted. Can't |
+ // generate more abbreviations without having to fix abbreviation indices. |
+ RecoverableError() << "Ignoring abbreviation: " << Record << "\n"; |
+ return Flags.getTryToRecover(); |
+ } |
if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { |
RecoverableError() |
<< "Uses illegal abbreviation index in define abbreviation record: " |
@@ -278,16 +377,11 @@ 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) |
+ if (Abbrev == nullptr) { |
+ markCurrentBlockWithOmittedAbbreviations(); |
return Flags.getTryToRecover(); |
+ } |
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) { |
Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); |
} else { |
@@ -314,10 +408,21 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
} |
UsesDefaultAbbrev = true; |
} |
- if (!UsesDefaultAbbrev |
- && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { |
- // Illegal abbreviation index found. |
+ if (!UsesDefaultAbbrev && !canApplyAbbreviation(Writer, Record)) { |
+ if (Writer.getAbbreviation(Record.Abbrev) != nullptr) { |
+ RecoverableError() << "Abbreviation doesn't apply to record: " |
+ << Record << "\n"; |
+ UsesDefaultAbbrev = true; |
+ if (!Flags.getTryToRecover()) |
+ return false; |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
+ return true; |
+ } |
if (Flags.getWriteBadAbbrevIndex()) { |
+ // The abbreviation is not understood by the bitcode writer, |
+ // and the flag value implies that we should still write it |
+ // out so that unit tests for this error condition can be |
+ // applied. |
Error() << "Uses illegal abbreviation index: " << Record << "\n"; |
// Generate bad abbreviation index so that the bitcode reader |
// can be tested, and then quit. |
@@ -329,9 +434,11 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
} |
RecoverableError() << "Uses illegal abbreviation index: " |
<< Record << "\n"; |
+ UsesDefaultAbbrev = true; |
if (!Flags.getTryToRecover()) |
return false; |
- UsesDefaultAbbrev = true; |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
+ return true; |
} |
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID |
&& Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { |
@@ -347,10 +454,8 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
SetBID = Record.Values[0]; |
return true; |
} |
- if (UsesDefaultAbbrev) |
- Writer.EmitRecord(Record.Code, Record.Values); |
- else |
- Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
+ break; |
} |
return true; |
} |
@@ -381,7 +486,7 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev( |
if (Index >= NumValues) { |
RecoverableError() |
<< "Malformed abbreviation found. Expects " << NumAbbreviations |
- << " operands but ound " << Count << ": " << Record << "\n"; |
+ << " operands but found " << Count << ": " << Record << "\n"; |
return deleteAbbrev(Abbrev); |
} |
switch (Record.Values[Index++]) { |
@@ -438,8 +543,8 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev( |
break; |
} |
default: |
- RecoverableError() << "Error: Bad literal flag " << Record.Values[Index] |
- << ": " << Record << "\n"; |
+ RecoverableError() << "Error: Bad abbreviation operand encoding " |
+ << Record.Values[Index-1] << ": " << Record << "\n"; |
return deleteAbbrev(Abbrev); |
} |
} |