diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/BitstreamReader.h index 18f6b9e011e..46e64d112ea 100644 --- a/include/llvm/Bitcode/BitstreamReader.h +++ b/include/llvm/Bitcode/BitstreamReader.h @@ -198,6 +198,8 @@ class BitstreamCursor { public: + static const size_t MaxChunkSize = sizeof(word_t) * 8; + BitstreamCursor() { init(nullptr); } explicit BitstreamCursor(BitstreamReader &R) { init(&R); } @@ -335,7 +337,7 @@ public: } word_t Read(unsigned NumBits) { - static const unsigned BitsInWord = sizeof(word_t) * 8; + static const unsigned BitsInWord = MaxChunkSize; assert(NumBits && NumBits <= BitsInWord && "Cannot return zero or more than BitsInWord bits!"); diff --git a/lib/Bitcode/Reader/BitstreamReader.cpp b/lib/Bitcode/Reader/BitstreamReader.cpp index beaaf7a7d66..ff37b8e4cfc 100644 --- a/lib/Bitcode/Reader/BitstreamReader.cpp +++ b/lib/Bitcode/Reader/BitstreamReader.cpp @@ -60,8 +60,10 @@ static uint64_t readAbbreviatedField(BitstreamCursor &Cursor, case BitCodeAbbrevOp::Blob: llvm_unreachable("Should not reach here"); case BitCodeAbbrevOp::Fixed: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); return Cursor.Read((unsigned)Op.getEncodingData()); case BitCodeAbbrevOp::VBR: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); return Cursor.ReadVBR64((unsigned)Op.getEncodingData()); case BitCodeAbbrevOp::Char6: return BitCodeAbbrevOp::DecodeChar6(Cursor.Read(6)); @@ -79,9 +81,11 @@ static void skipAbbreviatedField(BitstreamCursor &Cursor, case BitCodeAbbrevOp::Blob: llvm_unreachable("Should not reach here"); case BitCodeAbbrevOp::Fixed: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); Cursor.Read((unsigned)Op.getEncodingData()); break; case BitCodeAbbrevOp::VBR: + assert((unsigned)Op.getEncodingData() <= Cursor.MaxChunkSize); Cursor.ReadVBR64((unsigned)Op.getEncodingData()); break; case BitCodeAbbrevOp::Char6: @@ -264,6 +268,11 @@ void BitstreamCursor::ReadAbbrevRecord() { continue; } + if ((E == BitCodeAbbrevOp::Fixed || E == BitCodeAbbrevOp::VBR) && + Data > MaxChunkSize) + report_fatal_error( + "Fixed or VBR abbrev record with size > MaxChunkData"); + Abbv->Add(BitCodeAbbrevOp(E, Data)); } else Abbv->Add(BitCodeAbbrevOp(E)); diff --git a/test/Bitcode/Inputs/invalid-abbrev-fixed-size-too-big.bc b/test/Bitcode/Inputs/invalid-abbrev-fixed-size-too-big.bc new file mode 100644 index 00000000000..8fa28960d72 Binary files /dev/null and b/test/Bitcode/Inputs/invalid-abbrev-fixed-size-too-big.bc differ diff --git a/test/Bitcode/Inputs/invalid-abbrev-vbr-size-too-big.bc b/test/Bitcode/Inputs/invalid-abbrev-vbr-size-too-big.bc new file mode 100644 index 00000000000..35d00ba154b Binary files /dev/null and b/test/Bitcode/Inputs/invalid-abbrev-vbr-size-too-big.bc differ diff --git a/test/Bitcode/invalid.test b/test/Bitcode/invalid.test index 5431368a0ad..b6c2ed3e8d6 100644 --- a/test/Bitcode/invalid.test +++ b/test/Bitcode/invalid.test @@ -66,3 +66,10 @@ RUN: not llvm-dis -disable-output %p/Inputs/invalid-fp-shift.bc 2>&1 | \ RUN: FileCheck --check-prefix=FP-SHIFT %s FP-SHIFT: Invalid record + +RUN: not llvm-dis -disable-output %p/Inputs/invalid-abbrev-vbr-size-too-big.bc 2>&1 | \ +RUN: FileCheck --check-prefix=HUGE-ABBREV-OP %s +RUN: not llvm-dis -disable-output %p/Inputs/invalid-abbrev-fixed-size-too-big.bc 2>&1 | \ +RUN: FileCheck --check-prefix=HUGE-ABBREV-OP %s + +HUGE-ABBREV-OP: Fixed or VBR abbrev record with size > MaxChunkData