From: Zachary Turner Date: Sat, 3 Jun 2017 00:33:35 +0000 (+0000) Subject: [PDB] Fix use after free. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a5be24d937d73d48907b89712f53461b4f76bd3b;p=llvm [PDB] Fix use after free. Previously MappedBlockStream owned its own BumpPtrAllocator that it would allocate from when a read crossed a block boundary. This way it could still return the user a contiguous buffer of the requested size. However, It's not uncommon to open a stream, read some stuff, close it, and then save the information for later. After all, since the entire file is mapped into memory, the data should always be available as long as the file is open. Of course, the exception to this is when the data isn't *in* the file, but rather in some buffer that we temporarily allocated to present this contiguous view. And this buffer would get destroyed as soon as the strema was closed. The fix here is to force the user to specify the allocator, this way it can provide an allocator that has whatever lifetime it chooses. Differential Revision: https://reviews.llvm.org/D33858 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@304623 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/include/llvm/DebugInfo/MSF/MappedBlockStream.h index d68f5f70c83..36dce393fc6 100644 --- a/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ b/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -44,17 +44,19 @@ class MappedBlockStream : public BinaryStream { public: static std::unique_ptr createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, - BinaryStreamRef MsfData); + BinaryStreamRef MsfData, BumpPtrAllocator &Allocator); static std::unique_ptr createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData, - uint32_t StreamIndex); + uint32_t StreamIndex, BumpPtrAllocator &Allocator); static std::unique_ptr - createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData); + createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); static std::unique_ptr - createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData); + createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); llvm::support::endianness getEndian() const override { return llvm::support::little; @@ -67,9 +69,7 @@ public: uint32_t getLength() override; - uint32_t getNumBytesCopied() const; - - llvm::BumpPtrAllocator &getAllocator() { return Pool; } + llvm::BumpPtrAllocator &getAllocator() { return Allocator; } void invalidateCache(); @@ -79,7 +79,7 @@ public: protected: MappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &StreamLayout, - BinaryStreamRef MsfData); + BinaryStreamRef MsfData, BumpPtrAllocator &Allocator); private: const MSFStreamLayout &getStreamLayout() const { return StreamLayout; } @@ -94,7 +94,15 @@ private: BinaryStreamRef MsfData; typedef MutableArrayRef CacheEntry; - llvm::BumpPtrAllocator Pool; + + // We just store the allocator by reference. We use this to allocate + // contiguous memory for things like arrays or strings that cross a block + // boundary, and this memory is expected to outlive the stream. For example, + // someone could create a stream, read some stuff, then close the stream, and + // we would like outstanding references to fields to remain valid since the + // entire file is mapped anyway. Because of that, the user must supply the + // allocator to allocate broken records from. + BumpPtrAllocator &Allocator; DenseMap> CacheMap; }; @@ -102,18 +110,20 @@ class WritableMappedBlockStream : public WritableBinaryStream { public: static std::unique_ptr createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, - WritableBinaryStreamRef MsfData); + WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator); static std::unique_ptr createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, - uint32_t StreamIndex); + uint32_t StreamIndex, BumpPtrAllocator &Allocator); static std::unique_ptr createDirectoryStream(const MSFLayout &Layout, - WritableBinaryStreamRef MsfData); + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); static std::unique_ptr - createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData); + createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); llvm::support::endianness getEndian() const override { return llvm::support::little; @@ -139,7 +149,8 @@ public: protected: WritableMappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &StreamLayout, - WritableBinaryStreamRef MsfData); + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); private: MappedBlockStream ReadInterface; diff --git a/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/include/llvm/DebugInfo/PDB/Native/TpiStream.h index 17fba9991c2..0ee697696ca 100644 --- a/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -34,8 +34,7 @@ class TpiStream { friend class TpiStreamBuilder; public: - TpiStream(const PDBFile &File, - std::unique_ptr Stream); + TpiStream(PDBFile &File, std::unique_ptr Stream); ~TpiStream(); Error reload(); @@ -61,7 +60,7 @@ public: Error commit(); private: - const PDBFile &Pdb; + PDBFile &Pdb; std::unique_ptr Stream; std::unique_ptr Types; diff --git a/lib/DebugInfo/MSF/MappedBlockStream.cpp b/lib/DebugInfo/MSF/MappedBlockStream.cpp index dfdeb841421..faf2442bc94 100644 --- a/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ b/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -47,42 +47,46 @@ static Interval intersect(const Interval &I1, const Interval &I2) { MappedBlockStream::MappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &Layout, - BinaryStreamRef MsfData) - : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData) {} - -std::unique_ptr -MappedBlockStream::createStream(uint32_t BlockSize, - const MSFStreamLayout &Layout, - BinaryStreamRef MsfData) { + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) + : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData), + Allocator(Allocator) {} + +std::unique_ptr MappedBlockStream::createStream( + uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { return llvm::make_unique>( - BlockSize, Layout, MsfData); + BlockSize, Layout, MsfData, Allocator); } std::unique_ptr MappedBlockStream::createIndexedStream( - const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex) { + const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex, + BumpPtrAllocator &Allocator) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; SL.Blocks = Layout.StreamMap[StreamIndex]; SL.Length = Layout.StreamSizes[StreamIndex]; return llvm::make_unique>( - Layout.SB->BlockSize, SL, MsfData); + Layout.SB->BlockSize, SL, MsfData, Allocator); } std::unique_ptr MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, - BinaryStreamRef MsfData) { + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; - return createStream(Layout.SB->BlockSize, SL, MsfData); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); } std::unique_ptr MappedBlockStream::createFpmStream(const MSFLayout &Layout, - BinaryStreamRef MsfData) { + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); - return createStream(Layout.SB->BlockSize, SL, MsfData); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); } Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, @@ -148,7 +152,7 @@ Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, // into it, and return an ArrayRef to that. Do not touch existing pool // allocations, as existing clients may be holding a pointer which must // not be invalidated. - uint8_t *WriteBuffer = static_cast(Pool.Allocate(Size, 8)); + uint8_t *WriteBuffer = static_cast(Allocator.Allocate(Size, 8)); if (auto EC = readBytes(Offset, MutableArrayRef(WriteBuffer, Size))) return EC; @@ -269,10 +273,6 @@ Error MappedBlockStream::readBytes(uint32_t Offset, return Error::success(); } -uint32_t MappedBlockStream::getNumBytesCopied() const { - return static_cast(Pool.getBytesAllocated()); -} - void MappedBlockStream::invalidateCache() { CacheMap.shrink_and_clear(); } void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, @@ -313,43 +313,48 @@ void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, WritableMappedBlockStream::WritableMappedBlockStream( uint32_t BlockSize, const MSFStreamLayout &Layout, - WritableBinaryStreamRef MsfData) - : ReadInterface(BlockSize, Layout, MsfData), WriteInterface(MsfData) {} + WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator) + : ReadInterface(BlockSize, Layout, MsfData, Allocator), + WriteInterface(MsfData) {} std::unique_ptr WritableMappedBlockStream::createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, - WritableBinaryStreamRef MsfData) { + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { return llvm::make_unique>( - BlockSize, Layout, MsfData); + BlockSize, Layout, MsfData, Allocator); } std::unique_ptr WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, - uint32_t StreamIndex) { + uint32_t StreamIndex, + BumpPtrAllocator &Allocator) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; SL.Blocks = Layout.StreamMap[StreamIndex]; SL.Length = Layout.StreamSizes[StreamIndex]; - return createStream(Layout.SB->BlockSize, SL, MsfData); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); } std::unique_ptr WritableMappedBlockStream::createDirectoryStream( - const MSFLayout &Layout, WritableBinaryStreamRef MsfData) { + const MSFLayout &Layout, WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; - return createStream(Layout.SB->BlockSize, SL, MsfData); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); } std::unique_ptr WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, - WritableBinaryStreamRef MsfData) { + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); - return createStream(Layout.SB->BlockSize, SL, MsfData); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); } Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 9aea4acb74a..22c2ef31bd7 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -144,7 +144,7 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, if (Layout.ModDiStream != kInvalidStreamIndex) { auto NS = WritableMappedBlockStream::createIndexedStream( - MsfLayout, MsfBuffer, Layout.ModDiStream); + MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator()); WritableBinaryStreamRef Ref(*NS); BinaryStreamWriter SymbolWriter(Ref); // Write the symbols. diff --git a/lib/DebugInfo/PDB/Native/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp index 2f4fb6cc295..320b11dc5ca 100644 --- a/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -252,7 +252,7 @@ Error DbiStream::initializeSectionHeadersData() { return make_error(raw_error_code::no_stream); auto SHS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator()); size_t StreamLen = SHS->getLength(); if (StreamLen % sizeof(object::coff_section)) @@ -284,7 +284,7 @@ Error DbiStream::initializeFpoRecords() { return make_error(raw_error_code::no_stream); auto FS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator()); size_t StreamLen = FS->getLength(); if (StreamLen % sizeof(object::FpoData)) diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index 23c7456d777..55c20fdb9af 100644 --- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -357,8 +357,8 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = finalize()) return EC; - auto DbiS = WritableMappedBlockStream::createIndexedStream(Layout, MsfBuffer, - StreamDBI); + auto DbiS = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, StreamDBI, Allocator); BinaryStreamWriter Writer(*DbiS); if (auto EC = Writer.writeObject(*Header)) @@ -396,7 +396,7 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, if (Stream.StreamNumber == kInvalidStreamIndex) continue; auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, Stream.StreamNumber); + Layout, MsfBuffer, Stream.StreamNumber, Allocator); BinaryStreamWriter DbgStreamWriter(*WritableStream); if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) return EC; diff --git a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index f019d410328..707128f7efd 100644 --- a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -50,8 +50,8 @@ Error InfoStreamBuilder::finalizeMsfLayout() { Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer) const { - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB); + auto InfoS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, StreamPDB, Msf.getAllocator()); BinaryStreamWriter Writer(*InfoS); InfoStreamHeader H; diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 859295d2c7d..1254e23c73e 100644 --- a/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -146,7 +146,8 @@ Error PDBFile::parseFileHeaders() { // at getBlockSize() intervals, so we have to be compatible. // See the function fpmPn() for more information: // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 - auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer); + auto FpmStream = + MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator); BinaryStreamReader FpmReader(*FpmStream); ArrayRef FpmBytes; if (auto EC = FpmReader.readBytes(FpmBytes, @@ -184,7 +185,8 @@ Error PDBFile::parseStreamData() { // is exactly what we are attempting to parse. By specifying a custom // subclass of IPDBStreamData which only accesses the fields that have already // been parsed, we can avoid this and reuse MappedBlockStream. - auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer); + auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer, + Allocator); BinaryStreamReader Reader(*DS); if (auto EC = Reader.readInteger(NumStreams)) return EC; @@ -407,5 +409,6 @@ PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout, uint32_t StreamIndex) const { if (StreamIndex >= getNumStreams()) return make_error(raw_error_code::no_stream); - return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex); + return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex, + Allocator); } diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index c6568029ec5..2c6465e6fb2 100644 --- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -140,8 +140,8 @@ Error PDBFileBuilder::commit(StringRef Filename) { if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) return EC; - auto DirStream = - WritableMappedBlockStream::createDirectoryStream(Layout, Buffer); + auto DirStream = WritableMappedBlockStream::createDirectoryStream( + Layout, Buffer, Allocator); BinaryStreamWriter DW(*DirStream); if (auto EC = DW.writeInteger(Layout.StreamSizes.size())) return EC; @@ -158,8 +158,8 @@ Error PDBFileBuilder::commit(StringRef Filename) { if (!ExpectedSN) return ExpectedSN.takeError(); - auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, - *ExpectedSN); + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, *ExpectedSN, Allocator); BinaryStreamWriter NSWriter(*NS); if (auto EC = Strings.commit(NSWriter)) return EC; diff --git a/lib/DebugInfo/PDB/Native/TpiStream.cpp b/lib/DebugInfo/PDB/Native/TpiStream.cpp index 623afb371b5..67c803d3124 100644 --- a/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -32,8 +32,7 @@ using namespace llvm::support; using namespace llvm::msf; using namespace llvm::pdb; -TpiStream::TpiStream(const PDBFile &File, - std::unique_ptr Stream) +TpiStream::TpiStream(PDBFile &File, std::unique_ptr Stream) : Pdb(File), Stream(std::move(Stream)) {} TpiStream::~TpiStream() = default; @@ -77,7 +76,8 @@ Error TpiStream::reload() { "Invalid TPI hash stream index."); auto HS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex, + Pdb.getAllocator()); BinaryStreamReader HSR(*HS); // There should be a hash value for every type record, or no hashes at all. diff --git a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index 20456cc9782..9e943c7f114 100644 --- a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -147,8 +147,8 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = finalize()) return EC; - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); + auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, + Idx, Allocator); BinaryStreamWriter Writer(*InfoS); if (auto EC = Writer.writeObject(*Header)) @@ -159,8 +159,8 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, return EC; if (HashStreamIndex != kInvalidStreamIndex) { - auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, - HashStreamIndex); + auto HVS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, HashStreamIndex, Allocator); BinaryStreamWriter HW(*HVS); if (HashValueStream) { if (auto EC = HW.writeStreamRef(*HashValueStream)) diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 7268d0b888d..31c342cd0f5 100644 --- a/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -483,8 +483,8 @@ Error LLVMOutputStyle::dumpStreamBytes() { if (SI >= File.getNumStreams()) return make_error(raw_error_code::no_stream); - auto S = MappedBlockStream::createIndexedStream(File.getMsfLayout(), - File.getMsfBuffer(), SI); + auto S = MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator()); if (!S) continue; DictScope DD(P, "Stream"); @@ -791,7 +791,7 @@ Error LLVMOutputStyle::dumpDbiStream() { if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) { auto ModStreamData = MappedBlockStream::createIndexedStream( File.getMsfLayout(), File.getMsfBuffer(), - Modi.getModuleStreamIndex()); + Modi.getModuleStreamIndex(), File.getAllocator()); ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); if (auto EC = ModS.reload()) diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/tools/llvm-pdbdump/YAMLOutputStyle.cpp index 610b288c9ba..ee72b90b12d 100644 --- a/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -229,7 +229,8 @@ Error YAMLOutputStyle::dumpDbiStream() { continue; auto ModStreamData = msf::MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), ModiStream); + File.getMsfLayout(), File.getMsfBuffer(), ModiStream, + File.getAllocator()); pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData)); if (auto EC = ModS.reload()) diff --git a/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp index 14cd222d138..5f09416a9ff 100644 --- a/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp +++ b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp @@ -85,7 +85,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { for (auto &Modi : DS.modules()) { auto ModStreamData = pdb::MappedBlockStream::createIndexedStream( - Modi.Info.getModuleStreamIndex(), *File); + Modi.Info.getModuleStreamIndex(), *File, File->getAllocator()); if (!ModStreamData) { consumeError(ModStreamData.takeError()); return 0; diff --git a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp index 9d90e265df3..789fe515b01 100644 --- a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp +++ b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp @@ -70,6 +70,8 @@ public: return MSFStreamLayout{static_cast(Data.size()), Blocks}; } + BumpPtrAllocator Allocator; + private: std::vector Blocks; MutableArrayRef Data; @@ -77,7 +79,8 @@ private: TEST(MappedBlockStreamTest, NumBlocks) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); EXPECT_EQ(F.block_size(), S->getBlockSize()); EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks()); @@ -87,7 +90,8 @@ TEST(MappedBlockStreamTest, NumBlocks) { // and does not allocate. TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); BinaryStreamRef SR; @@ -102,13 +106,14 @@ TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) { // does not fail due to the length of the output buffer. TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA"; EXPECT_NO_ERROR(R.readFixedString(Str, 1)); EXPECT_EQ(Str, StringRef("A")); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Tests that a read which crosses a block boundary, but where the subsequent @@ -116,18 +121,18 @@ TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) { // not allocate memory. TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), - F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 2)); EXPECT_EQ(Str, StringRef("AB")); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); R.setOffset(6); EXPECT_NO_ERROR(R.readFixedString(Str, 4)); EXPECT_EQ(Str, StringRef("GHIJ")); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Tests that a read which crosses a block boundary and cannot be referenced @@ -135,62 +140,67 @@ TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) { // requested. TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 10)); EXPECT_EQ(Str, StringRef("ABCDEFGHIJ")); - EXPECT_EQ(10U, S->getNumBytesCopied()); + EXPECT_EQ(10U, F.Allocator.getBytesAllocated()); } // Test that an out of bounds read which doesn't cross a block boundary // fails and allocates no memory. TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; R.setOffset(10); EXPECT_ERROR(R.readFixedString(Str, 1)); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Test that an out of bounds read which crosses a contiguous block boundary // fails and allocates no memory. TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; R.setOffset(6); EXPECT_ERROR(R.readFixedString(Str, 5)); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Test that an out of bounds read which crosses a discontiguous block // boundary fails and allocates no memory. TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; EXPECT_ERROR(R.readFixedString(Str, 11)); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Tests that a read which is entirely contained within a single block but // beyond the end of a StreamRef fails. TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 1)); EXPECT_EQ(Str, StringRef("A")); - EXPECT_EQ(0U, S->getNumBytesCopied()); + EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); } // Tests that a read which is not aligned on the same boundary as a previous @@ -198,19 +208,20 @@ TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) { // previous allocation. TEST(MappedBlockStreamTest, UnalignedOverlappingRead) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str1; StringRef Str2; EXPECT_NO_ERROR(R.readFixedString(Str1, 7)); EXPECT_EQ(Str1, StringRef("ABCDEFG")); - EXPECT_EQ(7U, S->getNumBytesCopied()); + EXPECT_EQ(7U, F.Allocator.getBytesAllocated()); R.setOffset(2); EXPECT_NO_ERROR(R.readFixedString(Str2, 3)); EXPECT_EQ(Str2, StringRef("CDE")); EXPECT_EQ(Str1.data() + 2, Str2.data()); - EXPECT_EQ(7U, S->getNumBytesCopied()); + EXPECT_EQ(7U, F.Allocator.getBytesAllocated()); } // Tests that a read which is not aligned on the same boundary as a previous @@ -218,18 +229,19 @@ TEST(MappedBlockStreamTest, UnalignedOverlappingRead) { // still works correctly and allocates again from the shared pool. TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) { DiscontiguousStream F(BlocksAry, DataAry); - auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F); + auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, + F.Allocator); BinaryStreamReader R(*S); StringRef Str1; StringRef Str2; EXPECT_NO_ERROR(R.readFixedString(Str1, 6)); EXPECT_EQ(Str1, StringRef("ABCDEF")); - EXPECT_EQ(6U, S->getNumBytesCopied()); + EXPECT_EQ(6U, F.Allocator.getBytesAllocated()); R.setOffset(4); EXPECT_NO_ERROR(R.readFixedString(Str2, 4)); EXPECT_EQ(Str2, StringRef("EFGH")); - EXPECT_EQ(10U, S->getNumBytesCopied()); + EXPECT_EQ(10U, F.Allocator.getBytesAllocated()); } TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) { @@ -241,8 +253,8 @@ TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) { "LargeBuffer is not big enough"); DiscontiguousStream F(BlocksAry, Data); - auto S = WritableMappedBlockStream::createStream( - F.block_size(), F.layout(), F); + auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), + F, F.Allocator); ArrayRef Buffer; EXPECT_ERROR(S->writeBytes(0, ArrayRef(LargeBuffer))); @@ -254,8 +266,8 @@ TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) { TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) { static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; DiscontiguousStream F(BlocksAry, Data); - auto S = WritableMappedBlockStream::createStream( - F.block_size(), F.layout(), F); + auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), + F, F.Allocator); ArrayRef Buffer; EXPECT_NO_ERROR(S->readBytes(0, 1, Buffer)); @@ -287,8 +299,8 @@ TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) { 'T', 'G', '.', '0', '0'}; DiscontiguousStream F(BlocksAry, Data); - auto S = WritableMappedBlockStream::createStream( - F.block_size(), F.layout(), F); + auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), + F, F.Allocator); ArrayRef Buffer; EXPECT_NO_ERROR(S->writeBytes(0, TestData)); @@ -306,8 +318,8 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) { const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; DiscontiguousStream F(Blocks, Data); - auto S = WritableMappedBlockStream::createStream( - F.block_size(), F.layout(), F); + auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), + F, F.Allocator); enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 }; using support::ulittle32_t; @@ -399,7 +411,7 @@ TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) { DiscontiguousStream F(DestBlocks, DestData); auto DestStream = WritableMappedBlockStream::createStream( - F.block_size(), F.layout(), F); + F.block_size(), F.layout(), F, F.Allocator); // First write "Test Str" into the source stream. MutableBinaryByteStream SourceStream(SrcData, little); @@ -434,9 +446,9 @@ TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) { DiscontiguousStream SrcF(SrcBlocks, SrcData); auto Dest = WritableMappedBlockStream::createStream( - DestF.block_size(), DestF.layout(), DestF); + DestF.block_size(), DestF.layout(), DestF, DestF.Allocator); auto Src = WritableMappedBlockStream::createStream( - SrcF.block_size(), SrcF.layout(), SrcF); + SrcF.block_size(), SrcF.layout(), SrcF, SrcF.Allocator); // First write "Test Str" into the source stream. BinaryStreamWriter SourceWriter(*Src); @@ -457,4 +469,27 @@ TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) { EXPECT_EQ(Result, "Test Str"); } +TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) { + std::vector DataBytes(10); + MutableArrayRef Data(DataBytes); + const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; + + StringRef Str[] = {"Zero Str", ""}; + + DiscontiguousStream F(Blocks, Data); + { + auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), + F, F.Allocator); + + BinaryStreamReader Reader(*S); + BinaryStreamWriter Writer(*S); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeCString(Str[0])); + EXPECT_NO_ERROR(Reader.readCString(Str[1])); + EXPECT_EQ(Str[0], Str[1]); + } + + EXPECT_EQ(Str[0], Str[1]); +} + } // end anonymous namespace