[llvm-pdbdump] Correctly read data larger than a block

A bug was introduced when the code was refactored which resulted in a
bad memory access.

This fixes PR27565.

llvm-svn: 267953
This commit is contained in:
David Majnemer 2016-04-28 23:24:23 +00:00
parent 0ba164bbcb
commit 5baa2bc2e1
3 changed files with 990 additions and 78 deletions

View File

@ -13,9 +13,9 @@
using namespace llvm;
PDBStream::PDBStream(uint32_t StreamIdx, const PDBFile &File) : Pdb(File) {
this->StreamLength = Pdb.getStreamByteSize(StreamIdx);
this->BlockList = Pdb.getStreamBlockList(StreamIdx);
this->Offset = 0;
StreamLength = Pdb.getStreamByteSize(StreamIdx);
BlockList = Pdb.getStreamBlockList(StreamIdx);
Offset = 0;
}
std::error_code PDBStream::readInteger(uint32_t &Dest) {
@ -41,34 +41,20 @@ std::error_code PDBStream::readBytes(void *Dest, uint32_t Length) {
uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
// Make sure we aren't trying to read beyond the end of the stream.
if (this->Offset + Length > this->StreamLength)
if (Length > StreamLength)
return std::make_error_code(std::errc::bad_address);
if (Offset > StreamLength - Length)
return std::make_error_code(std::errc::bad_address);
// Modify the passed in offset to point to the data after the object.
Offset += Length;
// Handle the contiguous case: the offset + size stays within a block.
if (OffsetInBlock + Length <= Pdb.getBlockSize()) {
uint32_t StreamBlockAddr = this->BlockList[BlockNum];
StringRef Data = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize());
::memcpy(Dest, Data.data() + OffsetInBlock, Length);
return std::error_code();
}
// The non-contiguous case: we will stitch together non-contiguous chunks
uint32_t BytesLeft = Length;
uint32_t BytesWritten = 0;
char *WriteBuffer = static_cast<char *>(Dest);
while (BytesLeft > 0) {
uint32_t StreamBlockAddr = this->BlockList[BlockNum];
uint64_t StreamBlockOffset =
PDBFile::blockToOffset(StreamBlockAddr, Pdb.getBlockSize()) +
OffsetInBlock;
uint32_t StreamBlockAddr = BlockList[BlockNum];
StringRef Data = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize());
const char *ChunkStart = Data.data() + StreamBlockOffset;
const char *ChunkStart = Data.data() + OffsetInBlock;
uint32_t BytesInChunk =
std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock);
::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk);
@ -78,11 +64,15 @@ std::error_code PDBStream::readBytes(void *Dest, uint32_t Length) {
++BlockNum;
OffsetInBlock = 0;
}
// Modify the offset to point to the data after the object.
Offset += Length;
return std::error_code();
}
void PDBStream::setOffset(uint32_t O) { this->Offset = O; }
void PDBStream::setOffset(uint32_t O) { Offset = O; }
uint32_t PDBStream::getOffset() const { return this->Offset; }
uint32_t PDBStream::getOffset() const { return Offset; }
uint32_t PDBStream::getLength() const { return this->StreamLength; }
uint32_t PDBStream::getLength() const { return StreamLength; }

Binary file not shown.

File diff suppressed because it is too large Load Diff