[PATCH] D38833: BitstreamWriter: Better assertion when a block's abbrev code size is too small

Roman Lebedev via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 16 01:42:53 PDT 2018


lebedev.ri accepted this revision.
lebedev.ri added a comment.
This revision is now accepted and ready to land.

I would still like to see a test with `CodeLen`=32, and even a single call to `EmitRecordWithAbbrevImpl()`
(ubsan would then have caught the ub in the initial approach), but otherwise this seems reasonable to me.
I have no expertise in this code, so *please* wait for someone else to review this, too.



================
Comment at: include/llvm/Bitcode/BitstreamWriter.h:303
     assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
+    assert(Abbrev < (1U << CurCodeSize) && "Block code length is too small");
     const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get();
----------------
jordan_rose wrote:
> lebedev.ri wrote:
> > What is the expected range of `CurCodeSize` values?
> > This has UB if `CurCodeSize` == `32`.
> > It would be much safer to just use the variant with subtraction:
> > ```
> > assert(Abbrev <= (~(~0U >> (32-CurCodeSize))) && "Block code length is too small");
> > ```
> Good point. I don't think anyone's trying to use 32-bit record codes, but the [spec](http://llvm.org/docs/BitCodeFormat.html) doesn't seem to impose a limit. I'll switch it.
I think you want to move this assert to before the first use of `Abbrev` (before line 301)


================
Comment at: unittests/Bitcode/BitstreamWriterTest.cpp:75-182
+TEST(BitstreamWriterTest, trapOnSmallAbbrev_CodeLength2) {
+  SmallString<64> Buffer;
+  BitstreamWriter W(Buffer);
+  W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/2);
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(42U));
+  unsigned AbbrevCode = W.EmitAbbrev(std::move(Abbrev));
----------------
jordan_rose wrote:
> lebedev.ri wrote:
> > This looks rather monstrous, with a lot of duplication.
> > I was suggesting to just do:
> > ```
> > TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3_Ok) {
> >   SmallString<64> Buffer;
> >   BitstreamWriter W(Buffer);
> >   W.EnterBlockInfoBlock();
> >   auto Abbrev = std::make_shared<BitCodeAbbrev>();
> >   Abbrev->Add(BitCodeAbbrevOp(2U);
> >   (void)W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID,
> >                               std::move(Abbrev));
> >   W.ExitBlock();
> >   W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3);
> >   W.EmitRecordWithAbbrev(Abbrev, makeArrayRef(2U));
> >   W.ExitBlock();
> > }
> > 
> > TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3_LastOk) {
> >   SmallString<64> Buffer;
> >   BitstreamWriter W(Buffer);
> >   W.EnterBlockInfoBlock();
> >   auto Abbrev = std::make_shared<BitCodeAbbrev>();
> >   Abbrev->Add(BitCodeAbbrevOp(3U);
> >   (void)W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID,
> >                               std::move(Abbrev));
> >   W.ExitBlock();
> >   W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3);
> >   W.EmitRecordWithAbbrev(Abbrev, makeArrayRef(3U));
> >   W.ExitBlock();
> > }
> > 
> > TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3_NotOk) {
> >   SmallString<64> Buffer;
> >   BitstreamWriter W(Buffer);
> >   W.EnterBlockInfoBlock();
> >   auto Abbrev = std::make_shared<BitCodeAbbrev>();
> >   Abbrev->Add(BitCodeAbbrevOp(4U);
> >   (void)W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID,
> >                               std::move(Abbrev));
> >   W.ExitBlock();
> >   W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/3);
> >   W.EmitRecordWithAbbrev(Abbrev, makeArrayRef(4U));
> >   W.ExitBlock();
> > 
> > TEST(BitstreamWriterTest, trapOnSmallAbbrevUsingBlockInfo_CodeLength3_NoOverFlow) {
> >   SmallString<64> Buffer;
> >   BitstreamWriter W(Buffer);
> >   W.EnterBlockInfoBlock();
> >   auto Abbrev = std::make_shared<BitCodeAbbrev>();
> >   Abbrev->Add(BitCodeAbbrevOp(4294967295U); // i32 -1 
> >   (void)W.EmitBlockInfoAbbrev(bitc::FIRST_APPLICATION_BLOCKID,
> >                               std::move(Abbrev));
> >   W.ExitBlock();
> >   W.EnterSubblock(bitc::FIRST_APPLICATION_BLOCKID, /*CodeLen*/32);
> >   W.EmitRecordWithAbbrev(Abbrev, makeArrayRef(4294967295U));
> >   W.ExitBlock();
> > }
> > ```
> The values in the abbreviation have nothing to do with the abbreviation codes themselves; in order to get to code 8 you have to actually register 5 abbreviations. (0-3 are reserved.) I could probably pull out some of this into helper functions but I didn't feel like it was going to be super important.
Oh duh, i knew that, but kinda forgot :)


Repository:
  rL LLVM

https://reviews.llvm.org/D38833





More information about the llvm-commits mailing list