diff --git a/llvm/include/llvm/Bitstream/BitstreamReader.h b/llvm/include/llvm/Bitstream/BitstreamReader.h --- a/llvm/include/llvm/Bitstream/BitstreamReader.h +++ b/llvm/include/llvm/Bitstream/BitstreamReader.h @@ -294,6 +294,9 @@ BitsInCurWord = 0; } + /// Return the size of stream. + size_t size() const { return BitcodeBytes.size(); } + /// Skip to the end of the file. void skipToEnd() { NextChar = BitcodeBytes.size(); } }; @@ -364,17 +367,18 @@ explicit BitstreamCursor(MemoryBufferRef BitcodeBytes) : SimpleBitstreamCursor(BitcodeBytes) {} - using SimpleBitstreamCursor::canSkipToPos; using SimpleBitstreamCursor::AtEndOfStream; + using SimpleBitstreamCursor::canSkipToPos; + using SimpleBitstreamCursor::fillCurWord; using SimpleBitstreamCursor::getBitcodeBytes; using SimpleBitstreamCursor::GetCurrentBitNo; using SimpleBitstreamCursor::getCurrentByteNo; using SimpleBitstreamCursor::getPointerToByte; using SimpleBitstreamCursor::JumpToBit; - using SimpleBitstreamCursor::fillCurWord; using SimpleBitstreamCursor::Read; using SimpleBitstreamCursor::ReadVBR; using SimpleBitstreamCursor::ReadVBR64; + using SimpleBitstreamCursor::size; /// Return the number of bits used to encode an abbrev #. unsigned getAbbrevIDWidth() const { return CurCodeSize; } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -858,7 +858,7 @@ StringRef ProducerIdentification, LLVMContext &Context) : BitcodeReaderBase(std::move(Stream), Strtab), Context(Context), - ValueList(Context) { + ValueList(Context, Stream.size()) { this->ProducerIdentification = ProducerIdentification; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -130,8 +130,15 @@ LLVMContext &Context; + /// Maximum number of valid references. Forward references exceeding the + /// maximum must be invalid. + unsigned RefsUpperBound; + public: - BitcodeReaderMetadataList(LLVMContext &C) : Context(C) {} + BitcodeReaderMetadataList(LLVMContext &C, size_t RefsUpperBound) + : Context(C), + RefsUpperBound(std::min((size_t)std::numeric_limits::max(), + RefsUpperBound)) {} // vector compatibility methods unsigned size() const { return MetadataPtrs.size(); } @@ -218,6 +225,10 @@ } Metadata *BitcodeReaderMetadataList::getMetadataFwdRef(unsigned Idx) { + // Bail out for a clearly invalid value. + if (Idx >= RefsUpperBound) + return nullptr; + if (Idx >= size()) resize(Idx + 1); @@ -625,9 +636,10 @@ BitcodeReaderValueList &ValueList, std::function getTypeByID, bool IsImporting) - : MetadataList(TheModule.getContext()), ValueList(ValueList), - Stream(Stream), Context(TheModule.getContext()), TheModule(TheModule), - getTypeByID(std::move(getTypeByID)), IsImporting(IsImporting) {} + : MetadataList(TheModule.getContext(), Stream.size()), + ValueList(ValueList), Stream(Stream), Context(TheModule.getContext()), + TheModule(TheModule), getTypeByID(std::move(getTypeByID)), + IsImporting(IsImporting) {} Error parseMetadata(bool ModuleLevel); diff --git a/llvm/lib/Bitcode/Reader/ValueList.h b/llvm/lib/Bitcode/Reader/ValueList.h --- a/llvm/lib/Bitcode/Reader/ValueList.h +++ b/llvm/lib/Bitcode/Reader/ValueList.h @@ -46,8 +46,15 @@ ResolveConstantsTy ResolveConstants; LLVMContext &Context; + /// Maximum number of valid references. Forward references exceeding the + /// maximum must be invalid. + unsigned RefsUpperBound; + public: - BitcodeReaderValueList(LLVMContext &C) : Context(C) {} + BitcodeReaderValueList(LLVMContext &C, size_t RefsUpperBound) + : Context(C), + RefsUpperBound(std::min((size_t)std::numeric_limits::max(), + RefsUpperBound)) {} ~BitcodeReaderValueList() { assert(ResolveConstants.empty() && "Constants not resolved?"); diff --git a/llvm/lib/Bitcode/Reader/ValueList.cpp b/llvm/lib/Bitcode/Reader/ValueList.cpp --- a/llvm/lib/Bitcode/Reader/ValueList.cpp +++ b/llvm/lib/Bitcode/Reader/ValueList.cpp @@ -97,6 +97,10 @@ } Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, Type *Ty) { + // Bail out for a clearly invalid value. + if (Idx >= RefsUpperBound) + return nullptr; + if (Idx >= size()) resize(Idx + 1); @@ -114,8 +118,8 @@ Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty, Type **FullTy) { - // Bail out for a clearly invalid value. This would make us call resize(0) - if (Idx == std::numeric_limits::max()) + // Bail out for a clearly invalid value. + if (Idx >= RefsUpperBound) return nullptr; if (Idx >= size()) diff --git a/llvm/test/Bitcode/pr18704.ll b/llvm/test/Bitcode/pr18704.ll --- a/llvm/test/Bitcode/pr18704.ll +++ b/llvm/test/Bitcode/pr18704.ll @@ -1,6 +1,6 @@ ; RUN: not llvm-dis < %s.bc 2>&1 | FileCheck %s -; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Never resolved value found in function +; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Invalid record ; pr18704.ll.bc has an instruction referring to invalid type. ; The test checks that LLVM reports the error and doesn't access freed memory