Skip to content

Commit

Permalink
Fix StreamingMemoryObject to respect known object size.
Browse files Browse the repository at this point in the history
The existing code for method StreamingMemoryObject.fetchToPos does not respect
the corresonding call to setKnownObjectSize(). As a result, it allows the
StreamingMemoryObject to read bytes past the object size.

This patch provides a test case, and code to fix the problem.

Patch by Karl Schimpf
Differential Revision: http://reviews.llvm.org/D8931

llvm-svn: 237939
  • Loading branch information
dschuff committed May 21, 2015
1 parent 2868758 commit fcfd5ae
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 16 deletions.
23 changes: 12 additions & 11 deletions llvm/include/llvm/Support/StreamingMemoryObject.h
Expand Up @@ -59,26 +59,27 @@ class StreamingMemoryObject : public MemoryObject {
mutable size_t ObjectSize; // 0 if unknown, set if wrapper seen or EOF reached
mutable bool EOFReached;

// Fetch enough bytes such that Pos can be read or EOF is reached
// (i.e. BytesRead > Pos). Return true if Pos can be read.
// Unlike most of the functions in BitcodeReader, returns true on success.
// Most of the requests will be small, but we fetch at kChunkSize bytes
// at a time to avoid making too many potentially expensive GetBytes calls
// Fetch enough bytes such that Pos can be read (i.e. BytesRead >
// Pos). Returns true if Pos can be read. Unlike most of the
// functions in BitcodeReader, returns true on success. Most of the
// requests will be small, but we fetch at kChunkSize bytes at a
// time to avoid making too many potentially expensive GetBytes
// calls.
bool fetchToPos(size_t Pos) const {
if (EOFReached)
return Pos < ObjectSize;
while (Pos >= BytesRead) {
if (EOFReached)
return false;
Bytes.resize(BytesRead + BytesSkipped + kChunkSize);
size_t bytes = Streamer->GetBytes(&Bytes[BytesRead + BytesSkipped],
kChunkSize);
BytesRead += bytes;
if (bytes != kChunkSize) { // reached EOF/ran out of bytes
ObjectSize = BytesRead;
if (bytes == 0) { // reached EOF/ran out of bytes
if (ObjectSize == 0)
ObjectSize = BytesRead;
EOFReached = true;
break;
}
}
return Pos < BytesRead;
return !ObjectSize || Pos < ObjectSize;
}

StreamingMemoryObject(const StreamingMemoryObject&) = delete;
Expand Down
17 changes: 12 additions & 5 deletions llvm/lib/Support/StreamingMemoryObject.cpp
Expand Up @@ -73,7 +73,7 @@ namespace llvm {
// block until we actually want to read it.
bool StreamingMemoryObject::isValidAddress(uint64_t address) const {
if (ObjectSize && address < ObjectSize) return true;
return fetchToPos(address);
return fetchToPos(address);
}

uint64_t StreamingMemoryObject::getExtent() const {
Expand All @@ -87,13 +87,18 @@ uint64_t StreamingMemoryObject::getExtent() const {
uint64_t StreamingMemoryObject::readBytes(uint8_t *Buf, uint64_t Size,
uint64_t Address) const {
fetchToPos(Address + Size - 1);
if (Address >= BytesRead)
// Note: For wrapped bitcode files will set ObjectSize after the
// first call to fetchToPos. In such cases, ObjectSize can be
// smaller than BytesRead.
size_t MaxAddress =
(ObjectSize && ObjectSize < BytesRead) ? ObjectSize : BytesRead;
if (Address >= MaxAddress)
return 0;

uint64_t End = Address + Size;
if (End > BytesRead)
End = BytesRead;
assert(static_cast<int64_t>(End - Address) >= 0);
if (End > MaxAddress)
End = MaxAddress;
assert(End >= Address);
Size = End - Address;
memcpy(Buf, &Bytes[Address + BytesSkipped], Size);
return Size;
Expand All @@ -109,6 +114,8 @@ bool StreamingMemoryObject::dropLeadingBytes(size_t s) {
void StreamingMemoryObject::setKnownObjectSize(size_t size) {
ObjectSize = size;
Bytes.reserve(size);
if (ObjectSize <= BytesRead)
EOFReached = true;
}

MemoryObject *getNonStreamedMemoryObject(const unsigned char *Start,
Expand Down
9 changes: 9 additions & 0 deletions llvm/unittests/Support/StreamingMemoryObject.cpp
Expand Up @@ -27,3 +27,12 @@ TEST(StreamingMemoryObject, Test) {
StreamingMemoryObject O(DS);
EXPECT_TRUE(O.isValidAddress(32 * 1024));
}

TEST(StreamingMemoryObject, TestSetKnownObjectSize) {
auto *DS = new NullDataStreamer();
StreamingMemoryObject O(DS);
uint8_t Buf[32];
EXPECT_EQ((uint64_t) 16, O.readBytes(Buf, 16, 0));
O.setKnownObjectSize(24);
EXPECT_EQ((uint64_t) 8, O.readBytes(Buf, 16, 16));
}

0 comments on commit fcfd5ae

Please sign in to comment.