Index: include/llvm/Bitcode/BitstreamWriter.h =================================================================== --- include/llvm/Bitcode/BitstreamWriter.h +++ include/llvm/Bitcode/BitstreamWriter.h @@ -300,6 +300,8 @@ unsigned BlobLen = (unsigned) Blob.size(); unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV; assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!"); + assert(Abbrev <= (~0U >> (32-CurCodeSize)) && + "Block code length is too small"); const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get(); EmitCode(Abbrev); Index: unittests/Bitcode/BitstreamWriterTest.cpp =================================================================== --- unittests/Bitcode/BitstreamWriterTest.cpp +++ unittests/Bitcode/BitstreamWriterTest.cpp @@ -56,4 +56,131 @@ EXPECT_EQ(StringRef("str0"), Buffer); } -} // end namespace +TEST(BitstreamWriterTest, defineButDoNotUseAbbrevs) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/2); + // Define four more abbreviations, none of which fit in the code length. + // This should not actually cause any problems. + for (unsigned i = 0; i < 4; ++i) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(i * 10)); + (void)W.EmitAbbrev(std::move(Abbrev)); + } + W.ExitBlock(); +} + +#ifndef NDEBUG + +TEST(BitstreamWriterTest, trapOnSmallAbbrev_CodeLength2) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/2); + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(42U)); + unsigned AbbrevCode = W.EmitAbbrev(std::move(Abbrev)); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(AbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +TEST(BitstreamWriterTest, trapOnSmallAbbrev_CodeLength3) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3); + for (unsigned i = 0; i < 4; ++i) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(i * 10)); + unsigned AbbrevCode = W.EmitAbbrev(std::move(Abbrev)); + W.EmitRecordWithAbbrev(AbbrevCode, makeArrayRef(i * 10)); + } + auto TooBigAbbrev = std::make_shared(); + TooBigAbbrev->Add(BitCodeAbbrevOp(42U)); + unsigned TooBigAbbrevCode = W.EmitAbbrev(std::move(TooBigAbbrev)); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(TooBigAbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +TEST(BitstreamWriterTest, trapOnSmallAbbrev_CodeLength3_PastEnd) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3); + for (unsigned i = 0; i <= 4; ++i) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(i * 10)); + (void)W.EmitAbbrev(std::move(Abbrev)); + } + auto TooBigAbbrev = std::make_shared(); + TooBigAbbrev->Add(BitCodeAbbrevOp(42U)); + unsigned TooBigAbbrevCode = W.EmitAbbrev(std::move(TooBigAbbrev)); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(TooBigAbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength2) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterBlockInfoBlock(); + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(42U)); + unsigned AbbrevCode = W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID, + std::move(Abbrev)); + W.ExitBlock(); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/2); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(AbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterBlockInfoBlock(); + unsigned OkayAbbrevCodes[4]; + for (unsigned i = 0; i < 4; ++i) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(i * 10)); + OkayAbbrevCodes[i] = W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID, + std::move(Abbrev)); + } + auto TooBigAbbrev = std::make_shared(); + TooBigAbbrev->Add(BitCodeAbbrevOp(42U)); + unsigned TooBigAbbrevCode = + W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID, + std::move(TooBigAbbrev)); + W.ExitBlock(); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3); + for (unsigned i = 0; i < 4; ++i) + W.EmitRecordWithAbbrev(OkayAbbrevCodes[i], makeArrayRef(i * 10)); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(TooBigAbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3_PastEnd) { + SmallString<64> Buffer; + BitstreamWriter W(Buffer); + W.EnterBlockInfoBlock(); + for (unsigned i = 0; i <= 4; ++i) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(i * 10)); + (void)W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID, + std::move(Abbrev)); + } + auto TooBigAbbrev = std::make_shared(); + TooBigAbbrev->Add(BitCodeAbbrevOp(42U)); + unsigned TooBigAbbrevCode = + W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID, + std::move(TooBigAbbrev)); + W.ExitBlock(); + W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3); + EXPECT_DEATH({ W.EmitRecordWithAbbrev(TooBigAbbrevCode, makeArrayRef(42U)); }, + "Block code length is too small"); + W.ExitBlock(); +} + +#endif // NDEBUG + +} // end anonymous namespace