From 9f6583a3aaa48dd2c86bafc61f0816c19f21d29a Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Sun, 27 Mar 2016 22:49:32 +0000 Subject: [PATCH] Bitcode: Add SimpleBitstreamCursor::setArtificialByteLimit Allow users of SimpleBitstreamCursor to limit the number of bytes available to the cursor. This is preparation for instantiating a cursor that isn't allowed to load more bytes from a StreamingMemoryObject (just move around the ones already-loaded). llvm-svn: 264547 --- include/llvm/Bitcode/BitstreamReader.h | 24 +++++++- unittests/Bitcode/BitstreamReaderTest.cpp | 69 +++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/BitstreamReader.h index 801df459a99..a7b1392483f 100644 --- a/include/llvm/Bitcode/BitstreamReader.h +++ b/include/llvm/Bitcode/BitstreamReader.h @@ -171,7 +171,7 @@ public: if (BitsInCurWord != 0) return false; if (Size != 0) - return Size == NextChar; + return Size <= NextChar; fillCurWord(); return BitsInCurWord == 0; } @@ -351,6 +351,28 @@ public: /// Skip to the end of the file. void skipToEnd() { NextChar = R->getBitcodeBytes().getExtent(); } + + /// Prevent the cursor from reading past a byte boundary. + /// + /// Prevent the cursor from requesting byte reads past \c Limit. This is + /// useful when working with a cursor on a StreamingMemoryObject, when it's + /// desirable to avoid invalidating the result of getPointerToByte(). + /// + /// If \c Limit is on a word boundary, AtEndOfStream() will return true if + /// the cursor position reaches or exceeds \c Limit, regardless of the true + /// number of available bytes. Otherwise, AtEndOfStream() returns true when + /// it reaches or exceeds the next word boundary. + void setArtificialByteLimit(uint64_t Limit) { + assert(getCurrentByteNo() < Limit && "Move cursor before lowering limit"); + + // Round to word boundary. + if (Limit & (sizeof(word_t) - 1)) + Limit += sizeof(word_t) - Limit & (sizeof(word_t) - 1); + + // Only change size if the new one is lower. + if (!Size || Size > Limit) + Size = Limit; + } }; /// When advancing through a bitstream cursor, each advance can discover a few diff --git a/unittests/Bitcode/BitstreamReaderTest.cpp b/unittests/Bitcode/BitstreamReaderTest.cpp index 80285b84b32..9d3bf7bf14d 100644 --- a/unittests/Bitcode/BitstreamReaderTest.cpp +++ b/unittests/Bitcode/BitstreamReaderTest.cpp @@ -96,4 +96,73 @@ TEST(BitstreamReaderTest, jumpToPointer) { } } +TEST(BitstreamReaderTest, setArtificialByteLimit) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + BitstreamReader Reader(std::begin(Bytes), std::end(Bytes)); + SimpleBitstreamCursor Cursor(Reader); + + Cursor.setArtificialByteLimit(8); + while (!Cursor.AtEndOfStream()) + (void)Cursor.Read(1); + + EXPECT_EQ(8u, Cursor.getCurrentByteNo()); +} + +TEST(BitstreamReaderTest, setArtificialByteLimitNotWordBoundary) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + BitstreamReader Reader(std::begin(Bytes), std::end(Bytes)); + SimpleBitstreamCursor Cursor(Reader); + + Cursor.setArtificialByteLimit(5); + while (!Cursor.AtEndOfStream()) + (void)Cursor.Read(1); + + EXPECT_EQ(8u, Cursor.getCurrentByteNo()); +} + +TEST(BitstreamReaderTest, setArtificialByteLimitNot4ByteBoundary) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + BitstreamReader Reader(std::begin(Bytes), std::end(Bytes)); + SimpleBitstreamCursor Cursor(Reader); + + Cursor.setArtificialByteLimit(5); + while (!Cursor.AtEndOfStream()) + (void)Cursor.Read(1); + + EXPECT_EQ(8u, Cursor.getCurrentByteNo()); +} + +TEST(BitstreamReaderTest, setArtificialByteLimitPastTheEnd) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b}; + BitstreamReader Reader(std::begin(Bytes), std::end(Bytes)); + SimpleBitstreamCursor Cursor(Reader); + + // The size of the memory object isn't known yet. Set it too high and + // confirm that we don't read too far. + Cursor.setArtificialByteLimit(20); + while (!Cursor.AtEndOfStream()) + (void)Cursor.Read(1); + + EXPECT_EQ(12u, Cursor.getCurrentByteNo()); +} + +TEST(BitstreamReaderTest, setArtificialByteLimitPastTheEndKnown) { + uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b}; + BitstreamReader Reader(std::begin(Bytes), std::end(Bytes)); + SimpleBitstreamCursor Cursor(Reader); + + // Save the size of the memory object in the cursor. + while (!Cursor.AtEndOfStream()) + (void)Cursor.Read(1); + EXPECT_EQ(12u, Cursor.getCurrentByteNo()); + + Cursor.setArtificialByteLimit(20); + EXPECT_TRUE(Cursor.AtEndOfStream()); +} + } // end anonymous namespace