BitStream reader: propagate errors

The bitstream reader handles errors poorly. This has two effects:

 * Bugs in file handling (especially modules) manifest as an "unexpected end of
   file" crash
 * Users of clang as a library end up aborting because the code unconditionally
   calls `report_fatal_error`

The bitstream reader should be more resilient and return Expected / Error as
soon as an error is encountered, not way late like it does now. This patch
starts doing so and adopting the error handling where I think it makes sense.
There's plenty more to do: this patch propagates errors to be minimally useful,
and follow-ups will propagate them further and improve diagnostics.

https://bugs.llvm.org/show_bug.cgi?id=42311
<rdar://problem/33159405>

Differential Revision: https://reviews.llvm.org/D63518

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364464 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
JF Bastien 2019-06-26 19:50:12 +00:00
parent 8ded3ca9a9
commit 22d9c5c34d
9 changed files with 936 additions and 420 deletions

View File

@ -97,7 +97,7 @@ private:
unsigned BitsInCurWord = 0;
public:
static const size_t MaxChunkSize = sizeof(word_t) * 8;
static const constexpr size_t MaxChunkSize = sizeof(word_t) * 8;
SimpleBitstreamCursor() = default;
explicit SimpleBitstreamCursor(ArrayRef<uint8_t> BitcodeBytes)
@ -127,7 +127,7 @@ public:
ArrayRef<uint8_t> getBitcodeBytes() const { return BitcodeBytes; }
/// Reset the stream to the specified bit number.
void JumpToBit(uint64_t BitNo) {
Error JumpToBit(uint64_t BitNo) {
size_t ByteNo = size_t(BitNo/8) & ~(sizeof(word_t)-1);
unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1));
assert(canSkipToPos(ByteNo) && "Invalid location");
@ -137,8 +137,14 @@ public:
BitsInCurWord = 0;
// Skip over any bits that are already consumed.
if (WordBitNo)
Read(WordBitNo);
if (WordBitNo) {
if (Expected<word_t> Res = Read(WordBitNo))
return Error::success();
else
return Res.takeError();
}
return Error::success();
}
/// Get a pointer into the bitstream at the specified byte offset.
@ -154,9 +160,11 @@ public:
return getPointerToByte(BitNo / 8, NumBytes);
}
void fillCurWord() {
Error fillCurWord() {
if (NextChar >= BitcodeBytes.size())
report_fatal_error("Unexpected end of file");
return createStringError(std::errc::io_error,
"Unexpected end of file reading %u of %u bytes",
NextChar, BitcodeBytes.size());
// Read the next word from the stream.
const uint8_t *NextCharPtr = BitcodeBytes.data() + NextChar;
@ -175,9 +183,10 @@ public:
}
NextChar += BytesRead;
BitsInCurWord = BytesRead * 8;
return Error::success();
}
word_t Read(unsigned NumBits) {
Expected<word_t> Read(unsigned NumBits) {
static const unsigned BitsInWord = MaxChunkSize;
assert(NumBits && NumBits <= BitsInWord &&
@ -199,11 +208,14 @@ public:
word_t R = BitsInCurWord ? CurWord : 0;
unsigned BitsLeft = NumBits - BitsInCurWord;
fillCurWord();
if (Error fillResult = fillCurWord())
return std::move(fillResult);
// If we run out of data, abort.
if (BitsLeft > BitsInCurWord)
report_fatal_error("Unexpected end of file");
return createStringError(std::errc::io_error,
"Unexpected end of file reading %u of %u bits",
BitsInCurWord, BitsLeft);
word_t R2 = CurWord & (~word_t(0) >> (BitsInWord - BitsLeft));
@ -217,8 +229,12 @@ public:
return R;
}
uint32_t ReadVBR(unsigned NumBits) {
uint32_t Piece = Read(NumBits);
Expected<uint32_t> ReadVBR(unsigned NumBits) {
Expected<unsigned> MaybeRead = Read(NumBits);
if (!MaybeRead)
return MaybeRead;
uint32_t Piece = MaybeRead.get();
if ((Piece & (1U << (NumBits-1))) == 0)
return Piece;
@ -231,14 +247,21 @@ public:
return Result;
NextBit += NumBits-1;
Piece = Read(NumBits);
MaybeRead = Read(NumBits);
if (!MaybeRead)
return MaybeRead;
Piece = MaybeRead.get();
}
}
// Read a VBR that may have a value up to 64-bits in size. The chunk size of
// the VBR must still be <= 32 bits though.
uint64_t ReadVBR64(unsigned NumBits) {
uint32_t Piece = Read(NumBits);
Expected<uint64_t> ReadVBR64(unsigned NumBits) {
Expected<unsigned> MaybeRead = Read(NumBits);
if (!MaybeRead)
return MaybeRead;
uint32_t Piece = MaybeRead.get();
if ((Piece & (1U << (NumBits-1))) == 0)
return uint64_t(Piece);
@ -251,7 +274,10 @@ public:
return Result;
NextBit += NumBits-1;
Piece = Read(NumBits);
MaybeRead = Read(NumBits);
if (!MaybeRead)
return MaybeRead;
Piece = MaybeRead.get();
}
}
@ -365,12 +391,16 @@ public:
};
/// Advance the current bitstream, returning the next entry in the stream.
BitstreamEntry advance(unsigned Flags = 0) {
Expected<BitstreamEntry> advance(unsigned Flags = 0) {
while (true) {
if (AtEndOfStream())
return BitstreamEntry::getError();
unsigned Code = ReadCode();
Expected<unsigned> MaybeCode = ReadCode();
if (!MaybeCode)
return MaybeCode.takeError();
unsigned Code = MaybeCode.get();
if (Code == bitc::END_BLOCK) {
// Pop the end of the block unless Flags tells us not to.
if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd())
@ -378,14 +408,19 @@ public:
return BitstreamEntry::getEndBlock();
}
if (Code == bitc::ENTER_SUBBLOCK)
return BitstreamEntry::getSubBlock(ReadSubBlockID());
if (Code == bitc::ENTER_SUBBLOCK) {
if (Expected<unsigned> MaybeSubBlock = ReadSubBlockID())
return BitstreamEntry::getSubBlock(MaybeSubBlock.get());
else
return MaybeSubBlock.takeError();
}
if (Code == bitc::DEFINE_ABBREV &&
!(Flags & AF_DontAutoprocessAbbrevs)) {
// We read and accumulate abbrev's, the client can't do anything with
// them anyway.
ReadAbbrevRecord();
if (Error Err = ReadAbbrevRecord())
return std::move(Err);
continue;
}
@ -395,53 +430,66 @@ public:
/// This is a convenience function for clients that don't expect any
/// subblocks. This just skips over them automatically.
BitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) {
Expected<BitstreamEntry> advanceSkippingSubblocks(unsigned Flags = 0) {
while (true) {
// If we found a normal entry, return it.
BitstreamEntry Entry = advance(Flags);
Expected<BitstreamEntry> MaybeEntry = advance(Flags);
if (!MaybeEntry)
return MaybeEntry;
BitstreamEntry Entry = MaybeEntry.get();
if (Entry.Kind != BitstreamEntry::SubBlock)
return Entry;
// If we found a sub-block, just skip over it and check the next entry.
if (SkipBlock())
return BitstreamEntry::getError();
if (Error Err = SkipBlock())
return std::move(Err);
}
}
unsigned ReadCode() {
return Read(CurCodeSize);
}
Expected<unsigned> ReadCode() { return Read(CurCodeSize); }
// Block header:
// [ENTER_SUBBLOCK, blockid, newcodelen, <align4bytes>, blocklen]
/// Having read the ENTER_SUBBLOCK code, read the BlockID for the block.
unsigned ReadSubBlockID() {
return ReadVBR(bitc::BlockIDWidth);
}
Expected<unsigned> ReadSubBlockID() { return ReadVBR(bitc::BlockIDWidth); }
/// Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body
/// of this block. If the block record is malformed, return true.
bool SkipBlock() {
// Read and ignore the codelen value. Since we are skipping this block, we
// don't care what code widths are used inside of it.
ReadVBR(bitc::CodeLenWidth);
/// of this block.
Error SkipBlock() {
// Read and ignore the codelen value.
if (Expected<uint32_t> Res = ReadVBR(bitc::CodeLenWidth))
; // Since we are skipping this block, we don't care what code widths are
// used inside of it.
else
return Res.takeError();
SkipToFourByteBoundary();
size_t NumFourBytes = Read(bitc::BlockSizeWidth);
Expected<unsigned> MaybeNum = Read(bitc::BlockSizeWidth);
if (!MaybeNum)
return MaybeNum.takeError();
size_t NumFourBytes = MaybeNum.get();
// Check that the block wasn't partially defined, and that the offset isn't
// bogus.
size_t SkipTo = GetCurrentBitNo() + NumFourBytes*4*8;
if (AtEndOfStream() || !canSkipToPos(SkipTo/8))
return true;
size_t SkipTo = GetCurrentBitNo() + NumFourBytes * 4 * 8;
if (AtEndOfStream())
return createStringError(std::errc::illegal_byte_sequence,
"can't skip block: already at end of stream");
if (!canSkipToPos(SkipTo / 8))
return createStringError(std::errc::illegal_byte_sequence,
"can't skip to bit %zu from %" PRIu64, SkipTo,
GetCurrentBitNo());
JumpToBit(SkipTo);
return false;
if (Error Res = JumpToBit(SkipTo))
return Res;
return Error::success();
}
/// Having read the ENTER_SUBBLOCK abbrevid, enter the block, and return true
/// if the block has an error.
bool EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr);
/// Having read the ENTER_SUBBLOCK abbrevid, and enter the block.
Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr);
bool ReadBlockEnd() {
if (BlockScope.empty()) return true;
@ -476,22 +524,23 @@ public:
}
/// Read the current record and discard it, returning the code for the record.
unsigned skipRecord(unsigned AbbrevID);
Expected<unsigned> skipRecord(unsigned AbbrevID);
unsigned readRecord(unsigned AbbrevID, SmallVectorImpl<uint64_t> &Vals,
StringRef *Blob = nullptr);
Expected<unsigned> readRecord(unsigned AbbrevID,
SmallVectorImpl<uint64_t> &Vals,
StringRef *Blob = nullptr);
//===--------------------------------------------------------------------===//
// Abbrev Processing
//===--------------------------------------------------------------------===//
void ReadAbbrevRecord();
Error ReadAbbrevRecord();
/// Read and return a block info block from the bitstream. If an error was
/// encountered, return None.
///
/// \param ReadBlockInfoNames Whether to read block/record name information in
/// the BlockInfo block. Only llvm-bcanalyzer uses this.
Optional<BitstreamBlockInfo>
Expected<Optional<BitstreamBlockInfo>>
ReadBlockInfoBlock(bool ReadBlockInfoNames = false);
/// Set the block info to be used by this BitstreamCursor to interpret

View File

@ -1160,8 +1160,8 @@ private:
/// Create formatted StringError object.
template <typename... Ts>
Error createStringError(std::error_code EC, char const *Fmt,
const Ts &... Vals) {
inline Error createStringError(std::error_code EC, char const *Fmt,
const Ts &... Vals) {
std::string Buffer;
raw_string_ostream Stream(Buffer);
Stream << format(Fmt, Vals...);
@ -1170,6 +1170,12 @@ Error createStringError(std::error_code EC, char const *Fmt,
Error createStringError(std::error_code EC, char const *Msg);
template <typename... Ts>
inline Error createStringError(std::errc EC, char const *Fmt,
const Ts &... Vals) {
return createStringError(std::make_error_code(EC), Fmt, Vals...);
}
/// This class wraps a filename and another Error.
///
/// In some cases, an error needs to live along a 'source' name, in order to

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,8 @@ using namespace llvm;
// BitstreamCursor implementation
//===----------------------------------------------------------------------===//
/// EnterSubBlock - Having read the ENTER_SUBBLOCK abbrevid, enter
/// the block, and return true if the block has an error.
bool BitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) {
/// Having read the ENTER_SUBBLOCK abbrevid, enter the block.
Error BitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) {
// Save the current block's state on BlockScope.
BlockScope.push_back(Block(CurCodeSize));
BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
@ -34,21 +33,39 @@ bool BitstreamCursor::EnterSubBlock(unsigned BlockID, unsigned *NumWordsP) {
}
// Get the codesize of this block.
CurCodeSize = ReadVBR(bitc::CodeLenWidth);
// We can't read more than MaxChunkSize at a time
Expected<uint32_t> MaybeVBR = ReadVBR(bitc::CodeLenWidth);
if (!MaybeVBR)
return MaybeVBR.takeError();
CurCodeSize = MaybeVBR.get();
if (CurCodeSize > MaxChunkSize)
return true;
return llvm::createStringError(
std::errc::illegal_byte_sequence,
"can't read more than %zu at a time, trying to read %u", +MaxChunkSize,
CurCodeSize);
SkipToFourByteBoundary();
unsigned NumWords = Read(bitc::BlockSizeWidth);
if (NumWordsP) *NumWordsP = NumWords;
Expected<word_t> MaybeNum = Read(bitc::BlockSizeWidth);
if (!MaybeNum)
return MaybeNum.takeError();
word_t NumWords = MaybeNum.get();
if (NumWordsP)
*NumWordsP = NumWords;
// Validate that this block is sane.
return CurCodeSize == 0 || AtEndOfStream();
if (CurCodeSize == 0)
return llvm::createStringError(
std::errc::illegal_byte_sequence,
"can't enter sub-block: current code size is 0");
if (AtEndOfStream())
return llvm::createStringError(
std::errc::illegal_byte_sequence,
"can't enter sub block: already at end of stream");
return Error::success();
}
static uint64_t readAbbreviatedField(BitstreamCursor &Cursor,
const BitCodeAbbrevOp &Op) {
static Expected<uint64_t> readAbbreviatedField(BitstreamCursor &Cursor,
const BitCodeAbbrevOp &Op) {
assert(!Op.isLiteral() && "Not to be used with literals!");
// Decode the value as we are commanded.
@ -63,13 +80,16 @@ static uint64_t readAbbreviatedField(BitstreamCursor &Cursor,
assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize);
return Cursor.ReadVBR64((unsigned)Op.getEncodingData());
case BitCodeAbbrevOp::Char6:
return BitCodeAbbrevOp::DecodeChar6(Cursor.Read(6));
if (Expected<unsigned> Res = Cursor.Read(6))
return BitCodeAbbrevOp::DecodeChar6(Res.get());
else
return Res.takeError();
}
llvm_unreachable("invalid abbreviation encoding");
}
static void skipAbbreviatedField(BitstreamCursor &Cursor,
const BitCodeAbbrevOp &Op) {
static Error skipAbbreviatedField(BitstreamCursor &Cursor,
const BitCodeAbbrevOp &Op) {
assert(!Op.isLiteral() && "Not to be used with literals!");
// Decode the value as we are commanded.
@ -79,26 +99,43 @@ static void skipAbbreviatedField(BitstreamCursor &Cursor,
llvm_unreachable("Should not reach here");
case BitCodeAbbrevOp::Fixed:
assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize);
Cursor.Read((unsigned)Op.getEncodingData());
break;
if (Expected<unsigned> Res = Cursor.Read((unsigned)Op.getEncodingData()))
break;
else
return Res.takeError();
case BitCodeAbbrevOp::VBR:
assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize);
Cursor.ReadVBR64((unsigned)Op.getEncodingData());
break;
if (Expected<uint64_t> Res =
Cursor.ReadVBR64((unsigned)Op.getEncodingData()))
break;
else
return Res.takeError();
case BitCodeAbbrevOp::Char6:
Cursor.Read(6);
break;
if (Expected<unsigned> Res = Cursor.Read(6))
break;
else
return Res.takeError();
}
return ErrorSuccess();
}
/// skipRecord - Read the current record and discard it.
unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
Expected<unsigned> BitstreamCursor::skipRecord(unsigned AbbrevID) {
// Skip unabbreviated records by reading past their entries.
if (AbbrevID == bitc::UNABBREV_RECORD) {
unsigned Code = ReadVBR(6);
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeCode = ReadVBR(6);
if (!MaybeCode)
return MaybeCode.takeError();
unsigned Code = MaybeCode.get();
Expected<uint32_t> MaybeVBR = ReadVBR(6);
if (!MaybeVBR)
return MaybeVBR.get();
unsigned NumElts = MaybeVBR.get();
for (unsigned i = 0; i != NumElts; ++i)
(void)ReadVBR64(6);
if (Expected<uint64_t> Res = ReadVBR64(6))
; // Skip!
else
return Res.takeError();
return Code;
}
@ -110,8 +147,13 @@ unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
else {
if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array ||
CodeOp.getEncoding() == BitCodeAbbrevOp::Blob)
report_fatal_error("Abbreviation starts with an Array or a Blob");
Code = readAbbreviatedField(*this, CodeOp);
return llvm::createStringError(
std::errc::illegal_byte_sequence,
"Abbreviation starts with an Array or a Blob");
Expected<uint64_t> MaybeCode = readAbbreviatedField(*this, CodeOp);
if (!MaybeCode)
return MaybeCode.takeError();
Code = MaybeCode.get();
}
for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i < e; ++i) {
@ -121,13 +163,17 @@ unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
if (Op.getEncoding() != BitCodeAbbrevOp::Array &&
Op.getEncoding() != BitCodeAbbrevOp::Blob) {
skipAbbreviatedField(*this, Op);
if (Error Err = skipAbbreviatedField(*this, Op))
return std::move(Err);
continue;
}
if (Op.getEncoding() == BitCodeAbbrevOp::Array) {
// Array case. Read the number of elements as a vbr6.
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeNum = ReadVBR(6);
if (!MaybeNum)
return MaybeNum.takeError();
unsigned NumElts = MaybeNum.get();
// Get the element encoding.
assert(i+2 == e && "array op not second to last?");
@ -140,15 +186,22 @@ unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
report_fatal_error("Array element type can't be an Array or a Blob");
case BitCodeAbbrevOp::Fixed:
assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize);
JumpToBit(GetCurrentBitNo() + NumElts * EltEnc.getEncodingData());
if (Error Err = JumpToBit(GetCurrentBitNo() +
NumElts * EltEnc.getEncodingData()))
return std::move(Err);
break;
case BitCodeAbbrevOp::VBR:
assert((unsigned)EltEnc.getEncodingData() <= MaxChunkSize);
for (; NumElts; --NumElts)
ReadVBR64((unsigned)EltEnc.getEncodingData());
if (Expected<uint64_t> Res =
ReadVBR64((unsigned)EltEnc.getEncodingData()))
; // Skip!
else
return Res.takeError();
break;
case BitCodeAbbrevOp::Char6:
JumpToBit(GetCurrentBitNo() + NumElts * 6);
if (Error Err = JumpToBit(GetCurrentBitNo() + NumElts * 6))
return std::move(Err);
break;
}
continue;
@ -156,7 +209,10 @@ unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
assert(Op.getEncoding() == BitCodeAbbrevOp::Blob);
// Blob case. Read the number of bytes as a vbr6.
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeNum = ReadVBR(6);
if (!MaybeNum)
return MaybeNum.takeError();
unsigned NumElts = MaybeNum.get();
SkipToFourByteBoundary(); // 32-bit alignment
// Figure out where the end of this blob will be including tail padding.
@ -170,19 +226,30 @@ unsigned BitstreamCursor::skipRecord(unsigned AbbrevID) {
}
// Skip over the blob.
JumpToBit(NewEnd);
if (Error Err = JumpToBit(NewEnd))
return std::move(Err);
}
return Code;
}
unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
SmallVectorImpl<uint64_t> &Vals,
StringRef *Blob) {
Expected<unsigned> BitstreamCursor::readRecord(unsigned AbbrevID,
SmallVectorImpl<uint64_t> &Vals,
StringRef *Blob) {
if (AbbrevID == bitc::UNABBREV_RECORD) {
unsigned Code = ReadVBR(6);
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeCode = ReadVBR(6);
if (!MaybeCode)
return MaybeCode.takeError();
uint32_t Code = MaybeCode.get();
Expected<uint32_t> MaybeNumElts = ReadVBR(6);
if (!MaybeNumElts)
return MaybeNumElts.takeError();
uint32_t NumElts = MaybeNumElts.get();
for (unsigned i = 0; i != NumElts; ++i)
Vals.push_back(ReadVBR64(6));
if (Expected<uint64_t> MaybeVal = ReadVBR64(6))
Vals.push_back(MaybeVal.get());
else
return MaybeVal.takeError();
return Code;
}
@ -198,7 +265,10 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
if (CodeOp.getEncoding() == BitCodeAbbrevOp::Array ||
CodeOp.getEncoding() == BitCodeAbbrevOp::Blob)
report_fatal_error("Abbreviation starts with an Array or a Blob");
Code = readAbbreviatedField(*this, CodeOp);
if (Expected<uint64_t> MaybeCode = readAbbreviatedField(*this, CodeOp))
Code = MaybeCode.get();
else
return MaybeCode.takeError();
}
for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) {
@ -210,13 +280,19 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
if (Op.getEncoding() != BitCodeAbbrevOp::Array &&
Op.getEncoding() != BitCodeAbbrevOp::Blob) {
Vals.push_back(readAbbreviatedField(*this, Op));
if (Expected<uint64_t> MaybeVal = readAbbreviatedField(*this, Op))
Vals.push_back(MaybeVal.get());
else
return MaybeVal.takeError();
continue;
}
if (Op.getEncoding() == BitCodeAbbrevOp::Array) {
// Array case. Read the number of elements as a vbr6.
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeNumElts = ReadVBR(6);
if (!MaybeNumElts)
return MaybeNumElts.takeError();
uint32_t NumElts = MaybeNumElts.get();
// Get the element encoding.
if (i + 2 != e)
@ -232,22 +308,36 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
report_fatal_error("Array element type can't be an Array or a Blob");
case BitCodeAbbrevOp::Fixed:
for (; NumElts; --NumElts)
Vals.push_back(Read((unsigned)EltEnc.getEncodingData()));
if (Expected<SimpleBitstreamCursor::word_t> MaybeVal =
Read((unsigned)EltEnc.getEncodingData()))
Vals.push_back(MaybeVal.get());
else
return MaybeVal.takeError();
break;
case BitCodeAbbrevOp::VBR:
for (; NumElts; --NumElts)
Vals.push_back(ReadVBR64((unsigned)EltEnc.getEncodingData()));
if (Expected<uint64_t> MaybeVal =
ReadVBR64((unsigned)EltEnc.getEncodingData()))
Vals.push_back(MaybeVal.get());
else
return MaybeVal.takeError();
break;
case BitCodeAbbrevOp::Char6:
for (; NumElts; --NumElts)
Vals.push_back(BitCodeAbbrevOp::DecodeChar6(Read(6)));
if (Expected<SimpleBitstreamCursor::word_t> MaybeVal = Read(6))
Vals.push_back(BitCodeAbbrevOp::DecodeChar6(MaybeVal.get()));
else
return MaybeVal.takeError();
}
continue;
}
assert(Op.getEncoding() == BitCodeAbbrevOp::Blob);
// Blob case. Read the number of bytes as a vbr6.
unsigned NumElts = ReadVBR(6);
Expected<uint32_t> MaybeNumElts = ReadVBR(6);
if (!MaybeNumElts)
return MaybeNumElts.takeError();
uint32_t NumElts = MaybeNumElts.get();
SkipToFourByteBoundary(); // 32-bit alignment
// Figure out where the end of this blob will be including tail padding.
@ -265,7 +355,8 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
// Otherwise, inform the streamer that we need these bytes in memory. Skip
// over tail padding first, in case jumping to NewEnd invalidates the Blob
// pointer.
JumpToBit(NewEnd);
if (Error Err = JumpToBit(NewEnd))
return std::move(Err);
const char *Ptr = (const char *)getPointerToBit(CurBitPos, NumElts);
// If we can return a reference to the data, do so to avoid copying it.
@ -281,19 +372,35 @@ unsigned BitstreamCursor::readRecord(unsigned AbbrevID,
return Code;
}
void BitstreamCursor::ReadAbbrevRecord() {
Error BitstreamCursor::ReadAbbrevRecord() {
auto Abbv = std::make_shared<BitCodeAbbrev>();
unsigned NumOpInfo = ReadVBR(5);
Expected<uint32_t> MaybeNumOpInfo = ReadVBR(5);
if (!MaybeNumOpInfo)
return MaybeNumOpInfo.takeError();
unsigned NumOpInfo = MaybeNumOpInfo.get();
for (unsigned i = 0; i != NumOpInfo; ++i) {
bool IsLiteral = Read(1);
Expected<word_t> MaybeIsLiteral = Read(1);
if (!MaybeIsLiteral)
return MaybeIsLiteral.takeError();
bool IsLiteral = MaybeIsLiteral.get();
if (IsLiteral) {
Abbv->Add(BitCodeAbbrevOp(ReadVBR64(8)));
Expected<uint64_t> MaybeOp = ReadVBR64(8);
if (!MaybeOp)
return MaybeOp.takeError();
Abbv->Add(BitCodeAbbrevOp(MaybeOp.get()));
continue;
}
BitCodeAbbrevOp::Encoding E = (BitCodeAbbrevOp::Encoding)Read(3);
Expected<word_t> MaybeEncoding = Read(3);
if (!MaybeEncoding)
return MaybeEncoding.takeError();
BitCodeAbbrevOp::Encoding E =
(BitCodeAbbrevOp::Encoding)MaybeEncoding.get();
if (BitCodeAbbrevOp::hasEncodingData(E)) {
uint64_t Data = ReadVBR64(5);
Expected<uint64_t> MaybeData = ReadVBR64(5);
if (!MaybeData)
return MaybeData.takeError();
uint64_t Data = MaybeData.get();
// As a special case, handle fixed(0) (i.e., a fixed field with zero bits)
// and vbr(0) as a literal zero. This is decoded the same way, and avoids
@ -317,11 +424,14 @@ void BitstreamCursor::ReadAbbrevRecord() {
if (Abbv->getNumOperandInfos() == 0)
report_fatal_error("Abbrev record with no operands");
CurAbbrevs.push_back(std::move(Abbv));
return Error::success();
}
Optional<BitstreamBlockInfo>
Expected<Optional<BitstreamBlockInfo>>
BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) {
if (EnterSubBlock(bitc::BLOCKINFO_BLOCK_ID)) return None;
if (llvm::Error Err = EnterSubBlock(bitc::BLOCKINFO_BLOCK_ID))
return std::move(Err);
BitstreamBlockInfo NewBlockInfo;
@ -330,7 +440,11 @@ BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) {
// Read all the records for this module.
while (true) {
BitstreamEntry Entry = advanceSkippingSubblocks(AF_DontAutoprocessAbbrevs);
Expected<BitstreamEntry> MaybeEntry =
advanceSkippingSubblocks(AF_DontAutoprocessAbbrevs);
if (!MaybeEntry)
return MaybeEntry.takeError();
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
@ -346,7 +460,8 @@ BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) {
// Read abbrev records, associate them with CurBID.
if (Entry.ID == bitc::DEFINE_ABBREV) {
if (!CurBlockInfo) return None;
ReadAbbrevRecord();
if (Error Err = ReadAbbrevRecord())
return std::move(Err);
// ReadAbbrevRecord installs the abbrev in CurAbbrevs. Move it to the
// appropriate BlockInfo.
@ -357,22 +472,28 @@ BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) {
// Read a record.
Record.clear();
switch (readRecord(Entry.ID, Record)) {
default: break; // Default behavior, ignore unknown content.
case bitc::BLOCKINFO_CODE_SETBID:
if (Record.size() < 1) return None;
CurBlockInfo = &NewBlockInfo.getOrCreateBlockInfo((unsigned)Record[0]);
break;
case bitc::BLOCKINFO_CODE_BLOCKNAME: {
if (!CurBlockInfo) return None;
if (!ReadBlockInfoNames)
break; // Ignore name.
std::string Name;
for (unsigned i = 0, e = Record.size(); i != e; ++i)
Name += (char)Record[i];
CurBlockInfo->Name = Name;
break;
}
Expected<unsigned> MaybeBlockInfo = readRecord(Entry.ID, Record);
if (!MaybeBlockInfo)
return MaybeBlockInfo.takeError();
switch (MaybeBlockInfo.get()) {
default:
break; // Default behavior, ignore unknown content.
case bitc::BLOCKINFO_CODE_SETBID:
if (Record.size() < 1)
return None;
CurBlockInfo = &NewBlockInfo.getOrCreateBlockInfo((unsigned)Record[0]);
break;
case bitc::BLOCKINFO_CODE_BLOCKNAME: {
if (!CurBlockInfo)
return None;
if (!ReadBlockInfoNames)
break; // Ignore name.
std::string Name;
for (unsigned i = 0, e = Record.size(); i != e; ++i)
Name += (char)Record[i];
CurBlockInfo->Name = Name;
break;
}
case bitc::BLOCKINFO_CODE_SETRECORDNAME: {
if (!CurBlockInfo) return None;
if (!ReadBlockInfoNames)
@ -384,6 +505,6 @@ BitstreamCursor::ReadBlockInfoBlock(bool ReadBlockInfoNames) {
Name));
break;
}
}
}
}
}

View File

@ -674,8 +674,12 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
SmallVector<uint64_t, 64> Record;
// Get the abbrevs, and preload record positions to make them lazy-loadable.
while (true) {
BitstreamEntry Entry = IndexCursor.advanceSkippingSubblocks(
Expected<BitstreamEntry> MaybeEntry = IndexCursor.advanceSkippingSubblocks(
BitstreamCursor::AF_DontPopBlockAtEnd);
if (!MaybeEntry)
return MaybeEntry.takeError();
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case BitstreamEntry::SubBlock: // Handled for us already.
case BitstreamEntry::Error:
@ -687,14 +691,22 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
// The interesting case.
++NumMDRecordLoaded;
uint64_t CurrentPos = IndexCursor.GetCurrentBitNo();
auto Code = IndexCursor.skipRecord(Entry.ID);
Expected<unsigned> MaybeCode = IndexCursor.skipRecord(Entry.ID);
if (!MaybeCode)
return MaybeCode.takeError();
unsigned Code = MaybeCode.get();
switch (Code) {
case bitc::METADATA_STRINGS: {
// Rewind and parse the strings.
IndexCursor.JumpToBit(CurrentPos);
if (Error Err = IndexCursor.JumpToBit(CurrentPos))
return std::move(Err);
StringRef Blob;
Record.clear();
IndexCursor.readRecord(Entry.ID, Record, &Blob);
if (Expected<unsigned> MaybeRecord =
IndexCursor.readRecord(Entry.ID, Record, &Blob))
;
else
return MaybeRecord.takeError();
unsigned NumStrings = Record[0];
MDStringRef.reserve(NumStrings);
auto IndexNextMDString = [&](StringRef Str) {
@ -707,26 +719,37 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
case bitc::METADATA_INDEX_OFFSET: {
// This is the offset to the index, when we see this we skip all the
// records and load only an index to these.
IndexCursor.JumpToBit(CurrentPos);
if (Error Err = IndexCursor.JumpToBit(CurrentPos))
return std::move(Err);
Record.clear();
IndexCursor.readRecord(Entry.ID, Record);
if (Expected<unsigned> MaybeRecord =
IndexCursor.readRecord(Entry.ID, Record))
;
else
return MaybeRecord.takeError();
if (Record.size() != 2)
return error("Invalid record");
auto Offset = Record[0] + (Record[1] << 32);
auto BeginPos = IndexCursor.GetCurrentBitNo();
IndexCursor.JumpToBit(BeginPos + Offset);
Entry = IndexCursor.advanceSkippingSubblocks(
BitstreamCursor::AF_DontPopBlockAtEnd);
if (Error Err = IndexCursor.JumpToBit(BeginPos + Offset))
return std::move(Err);
Expected<BitstreamEntry> MaybeEntry =
IndexCursor.advanceSkippingSubblocks(
BitstreamCursor::AF_DontPopBlockAtEnd);
if (!MaybeEntry)
return MaybeEntry.takeError();
Entry = MaybeEntry.get();
assert(Entry.Kind == BitstreamEntry::Record &&
"Corrupted bitcode: Expected `Record` when trying to find the "
"Metadata index");
Record.clear();
auto Code = IndexCursor.readRecord(Entry.ID, Record);
(void)Code;
assert(Code == bitc::METADATA_INDEX && "Corrupted bitcode: Expected "
"`METADATA_INDEX` when trying "
"to find the Metadata index");
if (Expected<unsigned> MaybeCode =
IndexCursor.readRecord(Entry.ID, Record))
assert(MaybeCode.get() == bitc::METADATA_INDEX &&
"Corrupted bitcode: Expected `METADATA_INDEX` when trying to "
"find the Metadata index");
else
return MaybeCode.takeError();
// Delta unpack
auto CurrentValue = BeginPos;
GlobalMetadataBitPosIndex.reserve(Record.size());
@ -742,21 +765,33 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
return error("Corrupted Metadata block");
case bitc::METADATA_NAME: {
// Named metadata need to be materialized now and aren't deferred.
IndexCursor.JumpToBit(CurrentPos);
if (Error Err = IndexCursor.JumpToBit(CurrentPos))
return std::move(Err);
Record.clear();
unsigned Code = IndexCursor.readRecord(Entry.ID, Record);
assert(Code == bitc::METADATA_NAME);
unsigned Code;
if (Expected<unsigned> MaybeCode =
IndexCursor.readRecord(Entry.ID, Record)) {
Code = MaybeCode.get();
assert(Code == bitc::METADATA_NAME);
} else
return MaybeCode.takeError();
// Read name of the named metadata.
SmallString<8> Name(Record.begin(), Record.end());
Code = IndexCursor.ReadCode();
if (Expected<unsigned> MaybeCode = IndexCursor.ReadCode())
Code = MaybeCode.get();
else
return MaybeCode.takeError();
// Named Metadata comes in two parts, we expect the name to be followed
// by the node
Record.clear();
unsigned NextBitCode = IndexCursor.readRecord(Code, Record);
assert(NextBitCode == bitc::METADATA_NAMED_NODE);
(void)NextBitCode;
if (Expected<unsigned> MaybeNextBitCode =
IndexCursor.readRecord(Code, Record))
assert(MaybeNextBitCode.get() == bitc::METADATA_NAMED_NODE);
else
return MaybeNextBitCode.takeError();
// Read named metadata elements.
unsigned Size = Record.size();
@ -775,9 +810,14 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
case bitc::METADATA_GLOBAL_DECL_ATTACHMENT: {
// FIXME: we need to do this early because we don't materialize global
// value explicitly.
IndexCursor.JumpToBit(CurrentPos);
if (Error Err = IndexCursor.JumpToBit(CurrentPos))
return std::move(Err);
Record.clear();
IndexCursor.readRecord(Entry.ID, Record);
if (Expected<unsigned> MaybeRecord =
IndexCursor.readRecord(Entry.ID, Record))
;
else
return MaybeRecord.takeError();
if (Record.size() % 2 == 0)
return error("Invalid record");
unsigned ValueID = Record[0];
@ -845,8 +885,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
// skip the whole block in case we lazy-load.
auto EntryPos = Stream.GetCurrentBitNo();
if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
return error("Invalid record");
if (Error Err = Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
return Err;
SmallVector<uint64_t, 64> Record;
PlaceholderQueue Placeholders;
@ -871,9 +911,14 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
// Return at the beginning of the block, since it is easy to skip it
// entirely from there.
Stream.ReadBlockEnd(); // Pop the abbrev block context.
Stream.JumpToBit(EntryPos);
if (Stream.SkipBlock())
return error("Invalid record");
if (Error Err = IndexCursor.JumpToBit(EntryPos))
return Err;
if (Error Err = Stream.SkipBlock()) {
// FIXME this drops the error on the floor, which
// ThinLTO/X86/debuginfo-cu-import.ll relies on.
consumeError(std::move(Err));
return Error::success();
}
return Error::success();
}
// Couldn't load an index, fallback to loading all the block "old-style".
@ -883,7 +928,10 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
// Read all the records.
while (true) {
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
Expected<BitstreamEntry> MaybeEntry = Stream.advanceSkippingSubblocks();
if (!MaybeEntry)
return MaybeEntry.takeError();
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case BitstreamEntry::SubBlock: // Handled for us already.
@ -902,10 +950,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
Record.clear();
StringRef Blob;
++NumMDRecordLoaded;
unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
if (Error Err =
parseOneMetadata(Record, Code, Placeholders, Blob, NextMetadataNo))
return Err;
if (Expected<unsigned> MaybeCode =
Stream.readRecord(Entry.ID, Record, &Blob)) {
if (Error Err = parseOneMetadata(Record, MaybeCode.get(), Placeholders,
Blob, NextMetadataNo))
return Err;
} else
return MaybeCode.takeError();
}
}
@ -930,12 +981,25 @@ void MetadataLoader::MetadataLoaderImpl::lazyLoadOneMetadata(
}
SmallVector<uint64_t, 64> Record;
StringRef Blob;
IndexCursor.JumpToBit(GlobalMetadataBitPosIndex[ID - MDStringRef.size()]);
auto Entry = IndexCursor.advanceSkippingSubblocks();
if (Error Err = IndexCursor.JumpToBit(
GlobalMetadataBitPosIndex[ID - MDStringRef.size()]))
report_fatal_error("lazyLoadOneMetadata failed jumping: " +
toString(std::move(Err)));
Expected<BitstreamEntry> MaybeEntry = IndexCursor.advanceSkippingSubblocks();
if (!MaybeEntry)
// FIXME this drops the error on the floor.
report_fatal_error("lazyLoadOneMetadata failed advanceSkippingSubblocks: " +
toString(MaybeEntry.takeError()));
BitstreamEntry Entry = MaybeEntry.get();
++NumMDRecordLoaded;
unsigned Code = IndexCursor.readRecord(Entry.ID, Record, &Blob);
if (Error Err = parseOneMetadata(Record, Code, Placeholders, Blob, ID))
report_fatal_error("Can't lazyload MD");
if (Expected<unsigned> MaybeCode =
IndexCursor.readRecord(Entry.ID, Record, &Blob)) {
if (Error Err =
parseOneMetadata(Record, MaybeCode.get(), Placeholders, Blob, ID))
report_fatal_error("Can't lazyload MD, parseOneMetadata: " +
toString(std::move(Err)));
} else
report_fatal_error("Can't lazyload MD: " + toString(MaybeCode.takeError()));
}
/// Ensure that all forward-references and placeholders are resolved.
@ -1032,12 +1096,17 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
// Read name of the named metadata.
SmallString<8> Name(Record.begin(), Record.end());
Record.clear();
Code = Stream.ReadCode();
Expected<unsigned> MaybeCode = Stream.ReadCode();
if (!MaybeCode)
return MaybeCode.takeError();
Code = MaybeCode.get();
++NumMDRecordLoaded;
unsigned NextBitCode = Stream.readRecord(Code, Record);
if (NextBitCode != bitc::METADATA_NAMED_NODE)
return error("METADATA_NAME not followed by METADATA_NAMED_NODE");
if (Expected<unsigned> MaybeNextBitCode = Stream.readRecord(Code, Record)) {
if (MaybeNextBitCode.get() != bitc::METADATA_NAMED_NODE)
return error("METADATA_NAME not followed by METADATA_NAMED_NODE");
} else
return MaybeNextBitCode.takeError();
// Read named metadata elements.
unsigned Size = Record.size();
@ -1863,7 +1932,10 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataStrings(
if (R.AtEndOfStream())
return error("Invalid record: metadata strings bad length");
unsigned Size = R.ReadVBR(6);
Expected<uint32_t> MaybeSize = R.ReadVBR(6);
if (!MaybeSize)
return MaybeSize.takeError();
uint32_t Size = MaybeSize.get();
if (Strings.size() < Size)
return error("Invalid record: metadata strings truncated chars");
@ -1892,14 +1964,17 @@ Error MetadataLoader::MetadataLoaderImpl::parseGlobalObjectAttachment(
/// Parse metadata attachments.
Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
Function &F, const SmallVectorImpl<Instruction *> &InstructionList) {
if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
return error("Invalid record");
if (Error Err = Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
return Err;
SmallVector<uint64_t, 64> Record;
PlaceholderQueue Placeholders;
while (true) {
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
Expected<BitstreamEntry> MaybeEntry = Stream.advanceSkippingSubblocks();
if (!MaybeEntry)
return MaybeEntry.takeError();
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case BitstreamEntry::SubBlock: // Handled for us already.
@ -1916,7 +1991,10 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
// Read a metadata attachment record.
Record.clear();
++NumMDRecordLoaded;
switch (Stream.readRecord(Entry.ID, Record)) {
Expected<unsigned> MaybeRecord = Stream.readRecord(Entry.ID, Record);
if (!MaybeRecord)
return MaybeRecord.takeError();
switch (MaybeRecord.get()) {
default: // Default behavior: ignore.
break;
case bitc::METADATA_ATTACHMENT: {
@ -1990,14 +2068,17 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataKindRecord(
/// Parse the metadata kinds out of the METADATA_KIND_BLOCK.
Error MetadataLoader::MetadataLoaderImpl::parseMetadataKinds() {
if (Stream.EnterSubBlock(bitc::METADATA_KIND_BLOCK_ID))
return error("Invalid record");
if (Error Err = Stream.EnterSubBlock(bitc::METADATA_KIND_BLOCK_ID))
return Err;
SmallVector<uint64_t, 64> Record;
// Read all the records.
while (true) {
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
Expected<BitstreamEntry> MaybeEntry = Stream.advanceSkippingSubblocks();
if (!MaybeEntry)
return MaybeEntry.takeError();
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case BitstreamEntry::SubBlock: // Handled for us already.
@ -2013,8 +2094,10 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataKinds() {
// Read a record.
Record.clear();
++NumMDRecordLoaded;
unsigned Code = Stream.readRecord(Entry.ID, Record);
switch (Code) {
Expected<unsigned> MaybeCode = Stream.readRecord(Entry.ID, Record);
if (!MaybeCode)
return MaybeCode.takeError();
switch (MaybeCode.get()) {
default: // Default behavior: ignore.
break;
case bitc::METADATA_KIND: {

View File

@ -29,13 +29,13 @@ RUN: FileCheck --check-prefix=MISMATCHED-EXPLICIT-INVOKE %s
RUN: not llvm-dis -disable-output %p/Inputs/invalid-invoke-non-function-explicit-type.bc 2>&1 | \
RUN: FileCheck --check-prefix=NON-FUNCTION-EXPLICIT-INVOKE %s
INVALID-EMPTY: Invalid bitcode signature
INVALID-EMPTY: error: file too small to contain bitcode header
INVALID-ENCODING: Invalid encoding
BAD-ABBREV: Malformed block
UNEXPECTED-EOF: Malformed block
BAD-ABBREV-NUMBER: Malformed block
BAD-ABBREV: error: can't skip to bit 25870861920 from 96
UNEXPECTED-EOF: error: can't skip to bit 25870861920 from 96
BAD-ABBREV-NUMBER: error: can't skip to bit 25870861920 from 96
BAD-TYPE-TABLE-FORWARD-REF: Invalid TYPE table: Only named structs can be forward referenced
BAD-BITWIDTH: Malformed block
BAD-BITWIDTH: error: can't skip to bit 3616 from 96
BAD-ALIGN: Invalid alignment value
MISMATCHED-EXPLICIT-GEP: Explicit gep type does not match pointee type of pointer operand
MISMATCHED-EXPLICIT-LOAD: Explicit load/store type does not match pointee type of pointer operand
@ -154,7 +154,7 @@ EXTRACT-0-IDXS: EXTRACTVAL: Invalid instruction with 0 indices
RUN: not llvm-dis -disable-output %p/Inputs/invalid-load-ptr-type.bc 2>&1 | \
RUN: FileCheck --check-prefix=BAD-LOAD-PTR-TYPE %s
BAD-LOAD-PTR-TYPE: Malformed block
BAD-LOAD-PTR-TYPE: error: can't skip to bit 3616 from 96
RUN: not llvm-dis -disable-output %p/Inputs/invalid-inserted-value-type-mismatch.bc 2>&1 | \
RUN: FileCheck --check-prefix=INSERT-TYPE-MISMATCH %s
@ -164,7 +164,7 @@ INSERT-TYPE-MISMATCH: Inserted value type doesn't match aggregate type
RUN: not llvm-dis -disable-output %p/Inputs/invalid-code-len-width.bc 2>&1 | \
RUN: FileCheck --check-prefix=INVALID-CODELENWIDTH %s
INVALID-CODELENWIDTH: Malformed block
INVALID-CODELENWIDTH: error: can't skip to bit 3616 from 96
RUN: not llvm-dis -disable-output %p/Inputs/invalid-function-argument-type.bc 2>&1 | \
RUN: FileCheck --check-prefix=INVALID-ARGUMENT-TYPE %s

View File

@ -8,4 +8,4 @@
; CHECK-LIBS: llvm-lto: {{.*}}/Inputs/empty.bc: Could not read LTO input file: The file was not recognized as a valid object file
; RUN: not llvm-lto --thinlto %S/Inputs/empty.bc 2>&1 | FileCheck %s --check-prefix=CHECK-THIN
; CHECK-THIN: llvm-lto: error loading file '{{.*}}/Inputs/empty.bc': Invalid bitcode signature
; CHECK-THIN: llvm-lto: error loading file '{{.*}}/Inputs/empty.bc': file too small to contain bitcode header

View File

@ -449,15 +449,17 @@ struct PerBlockIDStats {
static std::map<unsigned, PerBlockIDStats> BlockIDStats;
/// ReportError - All bitcode analysis errors go through this function, making this a
/// good place to breakpoint if debugging.
/// All bitcode analysis errors go through this function, making this a good
/// place to breakpoint if debugging.
static bool ReportError(const Twine &Err) {
WithColor::error() << Err << "\n";
return true;
}
static bool ReportError(Error &&Err) {
return ReportError(toString(std::move(Err)));
}
static bool decodeMetadataStringsBlob(StringRef Indent,
ArrayRef<uint64_t> Record,
StringRef Blob) {
@ -478,7 +480,10 @@ static bool decodeMetadataStringsBlob(StringRef Indent,
if (R.AtEndOfStream())
return ReportError("bad length");
unsigned Size = R.ReadVBR(6);
Expected<uint32_t> MaybeSize = R.ReadVBR(6);
if (!MaybeSize)
return ReportError(MaybeSize.takeError());
uint32_t Size = MaybeSize.get();
if (Strings.size() < Size)
return ReportError("truncated chars");
@ -518,19 +523,24 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
bool DumpRecords = Dump;
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
Optional<BitstreamBlockInfo> NewBlockInfo =
Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
Stream.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
if (!MaybeNewBlockInfo)
return ReportError(MaybeNewBlockInfo.takeError());
Optional<BitstreamBlockInfo> NewBlockInfo =
std::move(MaybeNewBlockInfo.get());
if (!NewBlockInfo)
return ReportError("Malformed BlockInfoBlock");
BlockInfo = std::move(*NewBlockInfo);
Stream.JumpToBit(BlockBitStart);
if (Error Err = Stream.JumpToBit(BlockBitStart))
return ReportError(std::move(Err));
// It's not really interesting to dump the contents of the blockinfo block.
DumpRecords = false;
}
unsigned NumWords = 0;
if (Stream.EnterSubBlock(BlockID, &NumWords))
return ReportError("Malformed block record");
if (Error Err = Stream.EnterSubBlock(BlockID, &NumWords))
return ReportError(std::move(Err));
// Keep it for later, when we see a MODULE_HASH record
uint64_t BlockEntryPos = Stream.getCurrentByteNo();
@ -562,9 +572,12 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
uint64_t RecordStartBit = Stream.GetCurrentBitNo();
BitstreamEntry Entry =
Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
Expected<BitstreamEntry> MaybeEntry =
Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
if (!MaybeEntry)
return ReportError(MaybeEntry.takeError());
BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case BitstreamEntry::Error:
return ReportError("malformed bitcode file");
@ -599,7 +612,8 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
}
if (Entry.ID == bitc::DEFINE_ABBREV) {
Stream.ReadAbbrevRecord();
if (Error Err = Stream.ReadAbbrevRecord())
return ReportError(std::move(Err));
++BlockStats.NumAbbrevs;
continue;
}
@ -610,7 +624,10 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
StringRef Blob;
uint64_t CurrentRecordPos = Stream.GetCurrentBitNo();
unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
Expected<unsigned> MaybeCode = Stream.readRecord(Entry.ID, Record, &Blob);
if (!MaybeCode)
return ReportError(MaybeCode.takeError());
unsigned Code = MaybeCode.get();
// Increment the # occurrences of this code.
if (BlockStats.CodeFreq.size() <= Code)
@ -742,8 +759,12 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
}
// Make sure that we can skip the current record.
Stream.JumpToBit(CurrentRecordPos);
Stream.skipRecord(Entry.ID);
if (Error Err = Stream.JumpToBit(CurrentRecordPos))
return ReportError(std::move(Err));
if (Expected<unsigned> Skipped = Stream.skipRecord(Entry.ID))
; // Do nothing.
else
return ReportError(Skipped.takeError());
}
}
@ -755,27 +776,45 @@ static void PrintSize(uint64_t Bits) {
(double)Bits/8, (unsigned long)(Bits/32));
}
static CurStreamTypeType ReadSignature(BitstreamCursor &Stream) {
static Expected<CurStreamTypeType> ReadSignature(BitstreamCursor &Stream) {
auto tryRead = [&Stream](char &Dest, size_t size) -> Error {
if (Expected<SimpleBitstreamCursor::word_t> MaybeWord = Stream.Read(size))
Dest = MaybeWord.get();
else
return MaybeWord.takeError();
return Error::success();
};
char Signature[6];
Signature[0] = Stream.Read(8);
Signature[1] = Stream.Read(8);
if (Error Err = tryRead(Signature[0], 8))
return std::move(Err);
if (Error Err = tryRead(Signature[1], 8))
return std::move(Err);
// Autodetect the file contents, if it is one we know.
if (Signature[0] == 'C' && Signature[1] == 'P') {
Signature[2] = Stream.Read(8);
Signature[3] = Stream.Read(8);
if (Error Err = tryRead(Signature[2], 8))
return std::move(Err);
if (Error Err = tryRead(Signature[3], 8))
return std::move(Err);
if (Signature[2] == 'C' && Signature[3] == 'H')
return ClangSerializedASTBitstream;
} else if (Signature[0] == 'D' && Signature[1] == 'I') {
Signature[2] = Stream.Read(8);
Signature[3] = Stream.Read(8);
if (Error Err = tryRead(Signature[2], 8))
return std::move(Err);
if (Error Err = tryRead(Signature[3], 8))
return std::move(Err);
if (Signature[2] == 'A' && Signature[3] == 'G')
return ClangSerializedDiagnosticsBitstream;
} else {
Signature[2] = Stream.Read(4);
Signature[3] = Stream.Read(4);
Signature[4] = Stream.Read(4);
Signature[5] = Stream.Read(4);
if (Error Err = tryRead(Signature[2], 4))
return std::move(Err);
if (Error Err = tryRead(Signature[3], 4))
return std::move(Err);
if (Error Err = tryRead(Signature[4], 4))
return std::move(Err);
if (Error Err = tryRead(Signature[5], 4))
return std::move(Err);
if (Signature[0] == 'B' && Signature[1] == 'C' &&
Signature[2] == 0x0 && Signature[3] == 0xC &&
Signature[4] == 0xE && Signature[5] == 0xD)
@ -827,7 +866,10 @@ static bool openBitcodeFile(StringRef Path,
}
Stream = BitstreamCursor(ArrayRef<uint8_t>(BufPtr, EndBufPtr));
CurStreamType = ReadSignature(Stream);
Expected<CurStreamTypeType> MaybeSignature = ReadSignature(Stream);
if (!MaybeSignature)
return ReportError(MaybeSignature.takeError());
CurStreamType = std::move(MaybeSignature.get());
return false;
}
@ -853,21 +895,30 @@ static int AnalyzeBitcode() {
return true;
while (!BlockInfoCursor.AtEndOfStream()) {
unsigned Code = BlockInfoCursor.ReadCode();
if (Code != bitc::ENTER_SUBBLOCK)
Expected<unsigned> MaybeCode = BlockInfoCursor.ReadCode();
if (!MaybeCode)
return ReportError(MaybeCode.takeError());
if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
return ReportError("Invalid record at top-level in block info file");
unsigned BlockID = BlockInfoCursor.ReadSubBlockID();
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
Optional<BitstreamBlockInfo> NewBlockInfo =
Expected<unsigned> MaybeBlockID = BlockInfoCursor.ReadSubBlockID();
if (!MaybeBlockID)
return ReportError(MaybeBlockID.takeError());
if (MaybeBlockID.get() == bitc::BLOCKINFO_BLOCK_ID) {
Expected<Optional<BitstreamBlockInfo>> MaybeNewBlockInfo =
BlockInfoCursor.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
if (!MaybeNewBlockInfo)
return ReportError(MaybeNewBlockInfo.takeError());
Optional<BitstreamBlockInfo> NewBlockInfo =
std::move(MaybeNewBlockInfo.get());
if (!NewBlockInfo)
return ReportError("Malformed BlockInfoBlock in block info file");
BlockInfo = std::move(*NewBlockInfo);
break;
}
BlockInfoCursor.SkipBlock();
if (Error Err = BlockInfoCursor.SkipBlock())
return ReportError(std::move(Err));
}
}
@ -875,13 +926,17 @@ static int AnalyzeBitcode() {
// Parse the top-level structure. We only allow blocks at the top-level.
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
if (Code != bitc::ENTER_SUBBLOCK)
Expected<unsigned> MaybeCode = Stream.ReadCode();
if (!MaybeCode)
return ReportError(MaybeCode.takeError());
if (MaybeCode.get() != bitc::ENTER_SUBBLOCK)
return ReportError("Invalid record at top-level");
unsigned BlockID = Stream.ReadSubBlockID();
Expected<unsigned> MaybeBlockID = Stream.ReadSubBlockID();
if (!MaybeBlockID)
return ReportError(MaybeBlockID.takeError());
if (ParseBlock(Stream, BlockInfo, BlockID, 0, CurStreamType))
if (ParseBlock(Stream, BlockInfo, MaybeBlockID.get(), 0, CurStreamType))
return true;
++NumTopBlocks;
}

View File

@ -22,15 +22,17 @@ TEST(BitstreamReaderTest, AtEndOfStream) {
BitstreamCursor Cursor(Bytes);
EXPECT_FALSE(Cursor.AtEndOfStream());
(void)Cursor.Read(8);
Expected<SimpleBitstreamCursor::word_t> MaybeRead = Cursor.Read(8);
EXPECT_TRUE((bool)MaybeRead);
EXPECT_FALSE(Cursor.AtEndOfStream());
(void)Cursor.Read(24);
MaybeRead = Cursor.Read(24);
EXPECT_TRUE((bool)MaybeRead);
EXPECT_TRUE(Cursor.AtEndOfStream());
Cursor.JumpToBit(0);
EXPECT_FALSE(Cursor.JumpToBit(0));
EXPECT_FALSE(Cursor.AtEndOfStream());
Cursor.JumpToBit(32);
EXPECT_FALSE(Cursor.JumpToBit(32));
EXPECT_TRUE(Cursor.AtEndOfStream());
}
@ -40,7 +42,7 @@ TEST(BitstreamReaderTest, AtEndOfStreamJump) {
};
BitstreamCursor Cursor(Bytes);
Cursor.JumpToBit(32);
EXPECT_FALSE(Cursor.JumpToBit(32));
EXPECT_TRUE(Cursor.AtEndOfStream());
}
@ -56,7 +58,8 @@ TEST(BitstreamReaderTest, getCurrentByteNo) {
for (unsigned I = 0, E = 32; I != E; ++I) {
EXPECT_EQ(I / 8, Cursor.getCurrentByteNo());
(void)Cursor.Read(1);
Expected<SimpleBitstreamCursor::word_t> MaybeRead = Cursor.Read(1);
EXPECT_TRUE((bool)MaybeRead);
}
EXPECT_EQ(4u, Cursor.getCurrentByteNo());
}
@ -116,24 +119,33 @@ TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) {
// Header. Included in test so that we can run llvm-bcanalyzer to debug
// when there are problems.
ASSERT_EQ(Magic, Stream.Read(32));
Expected<SimpleBitstreamCursor::word_t> MaybeRead = Stream.Read(32);
ASSERT_TRUE((bool)MaybeRead);
ASSERT_EQ(Magic, MaybeRead.get());
// Block.
BitstreamEntry Entry =
Expected<BitstreamEntry> MaybeEntry =
Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
ASSERT_TRUE((bool)MaybeEntry);
BitstreamEntry Entry = MaybeEntry.get();
ASSERT_EQ(BitstreamEntry::SubBlock, Entry.Kind);
ASSERT_EQ(BlockID, Entry.ID);
ASSERT_FALSE(Stream.EnterSubBlock(BlockID));
// Abbreviation.
Entry = Stream.advance();
MaybeEntry = Stream.advance();
ASSERT_TRUE((bool)MaybeEntry);
Entry = MaybeEntry.get();
ASSERT_EQ(BitstreamEntry::Record, Entry.Kind);
ASSERT_EQ(AbbrevID, Entry.ID);
// Record.
StringRef BlobOut;
SmallVector<uint64_t, 1> Record;
ASSERT_EQ(RecordID, Stream.readRecord(Entry.ID, Record, &BlobOut));
Expected<unsigned> MaybeRecord =
Stream.readRecord(Entry.ID, Record, &BlobOut);
ASSERT_TRUE((bool)MaybeRecord);
ASSERT_EQ(RecordID, MaybeRecord.get());
EXPECT_TRUE(Record.empty());
EXPECT_EQ(BlobIn, BlobOut);
}
@ -143,7 +155,9 @@ TEST(BitstreamReaderTest, shortRead) {
uint8_t Bytes[] = {8, 7, 6, 5, 4, 3, 2, 1};
for (unsigned I = 1; I != 8; ++I) {
SimpleBitstreamCursor Cursor(ArrayRef<uint8_t>(Bytes, I));
EXPECT_EQ(8ull, Cursor.Read(8));
Expected<SimpleBitstreamCursor::word_t> MaybeRead = Cursor.Read(8);
ASSERT_TRUE((bool)MaybeRead);
EXPECT_EQ(8ull, MaybeRead.get());
}
}