1 //===- llvm/unittest/DebugInfo/MSF/MappedBlockStreamTest.cpp --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 10 #include "llvm/Support/BinaryByteStream.h" 11 #include "llvm/Support/BinaryStreamReader.h" 12 #include "llvm/Support/BinaryStreamRef.h" 13 #include "llvm/Support/BinaryStreamWriter.h" 14 #include "llvm/Testing/Support/Error.h" 15 16 #include "gmock/gmock.h" 17 #include "gtest/gtest.h" 18 19 20 using namespace llvm; 21 using namespace llvm::msf; 22 using namespace llvm::support; 23 24 namespace { 25 26 static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9}; 27 static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'}; 28 29 class DiscontiguousStream : public WritableBinaryStream { 30 public: 31 DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data) 32 : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {} 33 34 uint32_t block_size() const { return 1; } 35 uint32_t block_count() const { return Blocks.size(); } 36 37 endianness getEndian() const override { return little; } 38 39 Error readBytes(uint32_t Offset, uint32_t Size, 40 ArrayRef<uint8_t> &Buffer) override { 41 if (auto EC = checkOffsetForRead(Offset, Size)) 42 return EC; 43 Buffer = Data.slice(Offset, Size); 44 return Error::success(); 45 } 46 47 Error readLongestContiguousChunk(uint32_t Offset, 48 ArrayRef<uint8_t> &Buffer) override { 49 if (auto EC = checkOffsetForRead(Offset, 1)) 50 return EC; 51 Buffer = Data.drop_front(Offset); 52 return Error::success(); 53 } 54 55 uint32_t getLength() override { return Data.size(); } 56 57 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override { 58 if (auto EC = checkOffsetForWrite(Offset, SrcData.size())) 59 return EC; 60 ::memcpy(&Data[Offset], SrcData.data(), SrcData.size()); 61 return Error::success(); 62 } 63 Error commit() override { return Error::success(); } 64 65 MSFStreamLayout layout() const { 66 return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks}; 67 } 68 69 BumpPtrAllocator Allocator; 70 71 private: 72 std::vector<support::ulittle32_t> Blocks; 73 MutableArrayRef<uint8_t> Data; 74 }; 75 76 TEST(MappedBlockStreamTest, NumBlocks) { 77 DiscontiguousStream F(BlocksAry, DataAry); 78 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 79 F.Allocator); 80 EXPECT_EQ(F.block_size(), S->getBlockSize()); 81 EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks()); 82 } 83 84 // Tests that a read which is entirely contained within a single block works 85 // and does not allocate. 86 TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) { 87 DiscontiguousStream F(BlocksAry, DataAry); 88 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 89 F.Allocator); 90 91 BinaryStreamReader R(*S); 92 BinaryStreamRef SR; 93 EXPECT_THAT_ERROR(R.readStreamRef(SR, 0U), Succeeded()); 94 ArrayRef<uint8_t> Buffer; 95 EXPECT_THAT_ERROR(SR.readBytes(0U, 1U, Buffer), Failed()); 96 EXPECT_THAT_ERROR(R.readStreamRef(SR, 1U), Succeeded()); 97 EXPECT_THAT_ERROR(SR.readBytes(1U, 1U, Buffer), Failed()); 98 } 99 100 // Tests that a read which outputs into a full destination buffer works and 101 // does not fail due to the length of the output buffer. 102 TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) { 103 DiscontiguousStream F(BlocksAry, DataAry); 104 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 105 F.Allocator); 106 107 BinaryStreamReader R(*S); 108 StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA"; 109 EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded()); 110 EXPECT_EQ(Str, StringRef("A")); 111 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 112 } 113 114 // Tests that a read which crosses a block boundary, but where the subsequent 115 // blocks are still contiguous in memory to the previous block works and does 116 // not allocate memory. 117 TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) { 118 DiscontiguousStream F(BlocksAry, DataAry); 119 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 120 F.Allocator); 121 BinaryStreamReader R(*S); 122 StringRef Str; 123 EXPECT_THAT_ERROR(R.readFixedString(Str, 2), Succeeded()); 124 EXPECT_EQ(Str, StringRef("AB")); 125 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 126 127 R.setOffset(6); 128 EXPECT_THAT_ERROR(R.readFixedString(Str, 4), Succeeded()); 129 EXPECT_EQ(Str, StringRef("GHIJ")); 130 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 131 } 132 133 // Tests that a read which crosses a block boundary and cannot be referenced 134 // contiguously works and allocates only the precise amount of bytes 135 // requested. 136 TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) { 137 DiscontiguousStream F(BlocksAry, DataAry); 138 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 139 F.Allocator); 140 BinaryStreamReader R(*S); 141 StringRef Str; 142 EXPECT_THAT_ERROR(R.readFixedString(Str, 10), Succeeded()); 143 EXPECT_EQ(Str, StringRef("ABCDEFGHIJ")); 144 EXPECT_EQ(10U, F.Allocator.getBytesAllocated()); 145 } 146 147 // Test that an out of bounds read which doesn't cross a block boundary 148 // fails and allocates no memory. 149 TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) { 150 DiscontiguousStream F(BlocksAry, DataAry); 151 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 152 F.Allocator); 153 BinaryStreamReader R(*S); 154 StringRef Str; 155 156 R.setOffset(10); 157 EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Failed()); 158 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 159 } 160 161 // Test that an out of bounds read which crosses a contiguous block boundary 162 // fails and allocates no memory. 163 TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) { 164 DiscontiguousStream F(BlocksAry, DataAry); 165 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 166 F.Allocator); 167 BinaryStreamReader R(*S); 168 StringRef Str; 169 170 R.setOffset(6); 171 EXPECT_THAT_ERROR(R.readFixedString(Str, 5), Failed()); 172 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 173 } 174 175 // Test that an out of bounds read which crosses a discontiguous block 176 // boundary fails and allocates no memory. 177 TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) { 178 DiscontiguousStream F(BlocksAry, DataAry); 179 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 180 F.Allocator); 181 BinaryStreamReader R(*S); 182 StringRef Str; 183 184 EXPECT_THAT_ERROR(R.readFixedString(Str, 11), Failed()); 185 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 186 } 187 188 // Tests that a read which is entirely contained within a single block but 189 // beyond the end of a StreamRef fails. 190 TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) { 191 DiscontiguousStream F(BlocksAry, DataAry); 192 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 193 F.Allocator); 194 BinaryStreamReader R(*S); 195 StringRef Str; 196 EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded()); 197 EXPECT_EQ(Str, StringRef("A")); 198 EXPECT_EQ(0U, F.Allocator.getBytesAllocated()); 199 } 200 201 // Tests that a read which is not aligned on the same boundary as a previous 202 // cached request, but which is known to overlap that request, shares the 203 // previous allocation. 204 TEST(MappedBlockStreamTest, UnalignedOverlappingRead) { 205 DiscontiguousStream F(BlocksAry, DataAry); 206 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 207 F.Allocator); 208 BinaryStreamReader R(*S); 209 StringRef Str1; 210 StringRef Str2; 211 EXPECT_THAT_ERROR(R.readFixedString(Str1, 7), Succeeded()); 212 EXPECT_EQ(Str1, StringRef("ABCDEFG")); 213 EXPECT_EQ(7U, F.Allocator.getBytesAllocated()); 214 215 R.setOffset(2); 216 EXPECT_THAT_ERROR(R.readFixedString(Str2, 3), Succeeded()); 217 EXPECT_EQ(Str2, StringRef("CDE")); 218 EXPECT_EQ(Str1.data() + 2, Str2.data()); 219 EXPECT_EQ(7U, F.Allocator.getBytesAllocated()); 220 } 221 222 // Tests that a read which is not aligned on the same boundary as a previous 223 // cached request, but which only partially overlaps a previous cached request, 224 // still works correctly and allocates again from the shared pool. 225 TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) { 226 DiscontiguousStream F(BlocksAry, DataAry); 227 auto S = MappedBlockStream::createStream(F.block_size(), F.layout(), F, 228 F.Allocator); 229 BinaryStreamReader R(*S); 230 StringRef Str1; 231 StringRef Str2; 232 EXPECT_THAT_ERROR(R.readFixedString(Str1, 6), Succeeded()); 233 EXPECT_EQ(Str1, StringRef("ABCDEF")); 234 EXPECT_EQ(6U, F.Allocator.getBytesAllocated()); 235 236 R.setOffset(4); 237 EXPECT_THAT_ERROR(R.readFixedString(Str2, 4), Succeeded()); 238 EXPECT_EQ(Str2, StringRef("EFGH")); 239 EXPECT_EQ(10U, F.Allocator.getBytesAllocated()); 240 } 241 242 TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) { 243 static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; 244 static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5', 245 '6', '7', '8', '9', 'A'}; 246 static uint8_t SmallBuffer[] = {'0', '1', '2'}; 247 static_assert(sizeof(LargeBuffer) > sizeof(Data), 248 "LargeBuffer is not big enough"); 249 250 DiscontiguousStream F(BlocksAry, Data); 251 auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), 252 F, F.Allocator); 253 EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)), Failed()); 254 EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)), 255 Succeeded()); 256 EXPECT_THAT_ERROR(S->writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)), 257 Succeeded()); 258 EXPECT_THAT_ERROR(S->writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)), Failed()); 259 } 260 261 TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) { 262 static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; 263 DiscontiguousStream F(BlocksAry, Data); 264 auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), 265 F, F.Allocator); 266 ArrayRef<uint8_t> Buffer; 267 268 EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded()); 269 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A')); 270 EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded()); 271 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J')); 272 273 EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('J')), Succeeded()); 274 EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('A')), Succeeded()); 275 276 EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded()); 277 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J')); 278 EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded()); 279 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A')); 280 281 EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('A')), Succeeded()); 282 EXPECT_THAT_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('J')), Succeeded()); 283 284 EXPECT_THAT_ERROR(S->readBytes(0, 1, Buffer), Succeeded()); 285 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A')); 286 EXPECT_THAT_ERROR(S->readBytes(9, 1, Buffer), Succeeded()); 287 EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J')); 288 } 289 290 TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) { 291 static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'}; 292 static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'}; 293 static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I', 294 'T', 'G', '.', '0', '0'}; 295 296 DiscontiguousStream F(BlocksAry, Data); 297 auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), 298 F, F.Allocator); 299 ArrayRef<uint8_t> Buffer; 300 301 EXPECT_THAT_ERROR(S->writeBytes(0, TestData), Succeeded()); 302 // First just compare the memory, then compare the result of reading the 303 // string out. 304 EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected)); 305 306 EXPECT_THAT_ERROR(S->readBytes(0, 8, Buffer), Succeeded()); 307 EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData)); 308 } 309 310 TEST(MappedBlockStreamTest, TestWriteThenRead) { 311 std::vector<uint8_t> DataBytes(10); 312 MutableArrayRef<uint8_t> Data(DataBytes); 313 const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; 314 315 DiscontiguousStream F(Blocks, Data); 316 auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), 317 F, F.Allocator); 318 319 enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 }; 320 using support::ulittle32_t; 321 322 uint16_t u16[] = {31468, 0}; 323 uint32_t u32[] = {890723408, 0}; 324 MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2}; 325 StringRef ZStr[] = {"Zero Str", ""}; 326 StringRef FStr[] = {"Fixed Str", ""}; 327 uint8_t byteArray0[] = {'1', '2'}; 328 uint8_t byteArray1[] = {'0', '0'}; 329 ArrayRef<uint8_t> byteArrayRef0(byteArray0); 330 ArrayRef<uint8_t> byteArrayRef1(byteArray1); 331 ArrayRef<uint8_t> byteArray[] = {byteArrayRef0, byteArrayRef1}; 332 uint32_t intArr0[] = {890723408, 29082234}; 333 uint32_t intArr1[] = {890723408, 29082234}; 334 ArrayRef<uint32_t> intArray[] = {intArr0, intArr1}; 335 336 BinaryStreamReader Reader(*S); 337 BinaryStreamWriter Writer(*S); 338 EXPECT_THAT_ERROR(Writer.writeInteger(u16[0]), Succeeded()); 339 EXPECT_THAT_ERROR(Reader.readInteger(u16[1]), Succeeded()); 340 EXPECT_EQ(u16[0], u16[1]); 341 EXPECT_EQ(std::vector<uint8_t>({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}), 342 DataBytes); 343 344 Reader.setOffset(0); 345 Writer.setOffset(0); 346 ::memset(DataBytes.data(), 0, 10); 347 EXPECT_THAT_ERROR(Writer.writeInteger(u32[0]), Succeeded()); 348 EXPECT_THAT_ERROR(Reader.readInteger(u32[1]), Succeeded()); 349 EXPECT_EQ(u32[0], u32[1]); 350 EXPECT_EQ(std::vector<uint8_t>({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}), 351 DataBytes); 352 353 Reader.setOffset(0); 354 Writer.setOffset(0); 355 ::memset(DataBytes.data(), 0, 10); 356 EXPECT_THAT_ERROR(Writer.writeEnum(Enum[0]), Succeeded()); 357 EXPECT_THAT_ERROR(Reader.readEnum(Enum[1]), Succeeded()); 358 EXPECT_EQ(Enum[0], Enum[1]); 359 EXPECT_EQ(std::vector<uint8_t>({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}), 360 DataBytes); 361 362 Reader.setOffset(0); 363 Writer.setOffset(0); 364 ::memset(DataBytes.data(), 0, 10); 365 EXPECT_THAT_ERROR(Writer.writeCString(ZStr[0]), Succeeded()); 366 EXPECT_THAT_ERROR(Reader.readCString(ZStr[1]), Succeeded()); 367 EXPECT_EQ(ZStr[0], ZStr[1]); 368 EXPECT_EQ( 369 std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}), 370 DataBytes); 371 372 Reader.setOffset(0); 373 Writer.setOffset(0); 374 ::memset(DataBytes.data(), 0, 10); 375 EXPECT_THAT_ERROR(Writer.writeFixedString(FStr[0]), Succeeded()); 376 EXPECT_THAT_ERROR(Reader.readFixedString(FStr[1], FStr[0].size()), 377 Succeeded()); 378 EXPECT_EQ(FStr[0], FStr[1]); 379 EXPECT_EQ( 380 std::vector<uint8_t>({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}), 381 DataBytes); 382 383 Reader.setOffset(0); 384 Writer.setOffset(0); 385 ::memset(DataBytes.data(), 0, 10); 386 EXPECT_THAT_ERROR(Writer.writeArray(byteArray[0]), Succeeded()); 387 EXPECT_THAT_ERROR(Reader.readArray(byteArray[1], byteArray[0].size()), 388 Succeeded()); 389 EXPECT_EQ(byteArray[0], byteArray[1]); 390 EXPECT_EQ(std::vector<uint8_t>({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}), 391 DataBytes); 392 393 Reader.setOffset(0); 394 Writer.setOffset(0); 395 ::memset(DataBytes.data(), 0, 10); 396 EXPECT_THAT_ERROR(Writer.writeArray(intArray[0]), Succeeded()); 397 EXPECT_THAT_ERROR(Reader.readArray(intArray[1], intArray[0].size()), 398 Succeeded()); 399 EXPECT_EQ(intArray[0], intArray[1]); 400 } 401 402 TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) { 403 std::vector<uint8_t> DestDataBytes(10); 404 MutableArrayRef<uint8_t> DestData(DestDataBytes); 405 const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; 406 407 std::vector<uint8_t> SrcDataBytes(10); 408 MutableArrayRef<uint8_t> SrcData(SrcDataBytes); 409 410 DiscontiguousStream F(DestBlocks, DestData); 411 auto DestStream = WritableMappedBlockStream::createStream( 412 F.block_size(), F.layout(), F, F.Allocator); 413 414 // First write "Test Str" into the source stream. 415 MutableBinaryByteStream SourceStream(SrcData, little); 416 BinaryStreamWriter SourceWriter(SourceStream); 417 EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded()); 418 EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>( 419 {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0})); 420 421 // Then write the source stream into the dest stream. 422 BinaryStreamWriter DestWriter(*DestStream); 423 EXPECT_THAT_ERROR(DestWriter.writeStreamRef(SourceStream), Succeeded()); 424 EXPECT_EQ(DestDataBytes, std::vector<uint8_t>( 425 {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); 426 427 // Then read the string back out of the dest stream. 428 StringRef Result; 429 BinaryStreamReader DestReader(*DestStream); 430 EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded()); 431 EXPECT_EQ(Result, "Test Str"); 432 } 433 434 TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) { 435 std::vector<uint8_t> DestDataBytes(10); 436 MutableArrayRef<uint8_t> DestData(DestDataBytes); 437 const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; 438 439 std::vector<uint8_t> SrcDataBytes(10); 440 MutableArrayRef<uint8_t> SrcData(SrcDataBytes); 441 const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9}; 442 443 DiscontiguousStream DestF(DestBlocks, DestData); 444 DiscontiguousStream SrcF(SrcBlocks, SrcData); 445 446 auto Dest = WritableMappedBlockStream::createStream( 447 DestF.block_size(), DestF.layout(), DestF, DestF.Allocator); 448 auto Src = WritableMappedBlockStream::createStream( 449 SrcF.block_size(), SrcF.layout(), SrcF, SrcF.Allocator); 450 451 // First write "Test Str" into the source stream. 452 BinaryStreamWriter SourceWriter(*Src); 453 EXPECT_THAT_ERROR(SourceWriter.writeCString("Test Str"), Succeeded()); 454 EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>( 455 {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0})); 456 457 // Then write the source stream into the dest stream. 458 BinaryStreamWriter DestWriter(*Dest); 459 EXPECT_THAT_ERROR(DestWriter.writeStreamRef(*Src), Succeeded()); 460 EXPECT_EQ(DestDataBytes, std::vector<uint8_t>( 461 {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); 462 463 // Then read the string back out of the dest stream. 464 StringRef Result; 465 BinaryStreamReader DestReader(*Dest); 466 EXPECT_THAT_ERROR(DestReader.readCString(Result), Succeeded()); 467 EXPECT_EQ(Result, "Test Str"); 468 } 469 470 TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) { 471 std::vector<uint8_t> DataBytes(10); 472 MutableArrayRef<uint8_t> Data(DataBytes); 473 const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; 474 475 StringRef Str[] = {"Zero Str", ""}; 476 477 DiscontiguousStream F(Blocks, Data); 478 { 479 auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(), 480 F, F.Allocator); 481 482 BinaryStreamReader Reader(*S); 483 BinaryStreamWriter Writer(*S); 484 ::memset(DataBytes.data(), 0, 10); 485 EXPECT_THAT_ERROR(Writer.writeCString(Str[0]), Succeeded()); 486 EXPECT_THAT_ERROR(Reader.readCString(Str[1]), Succeeded()); 487 EXPECT_EQ(Str[0], Str[1]); 488 } 489 490 EXPECT_EQ(Str[0], Str[1]); 491 } 492 } // namespace 493 494 MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") { 495 uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize); 496 ArrayRef<uint8_t> BufferRef = makeArrayRef(arg); 497 BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize); 498 return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; }); 499 } 500 501 namespace { 502 TEST(MappedBlockStreamTest, CreateFpmStream) { 503 BumpPtrAllocator Allocator; 504 SuperBlock SB; 505 MSFLayout L; 506 L.SB = &SB; 507 508 SB.FreeBlockMapBlock = 1; 509 SB.BlockSize = 4096; 510 511 constexpr uint32_t NumFileBlocks = 4096 * 4; 512 513 std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize); 514 MutableBinaryByteStream MsfStream(MsfBuffer, llvm::support::little); 515 516 SB.NumBlocks = NumFileBlocks; 517 auto FpmStream = 518 WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator); 519 // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4 520 // blocks. This translates to 1 FPM block. 521 EXPECT_EQ(2048u, FpmStream->getLength()); 522 EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size()); 523 EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]); 524 // All blocks from FPM1 should be 1 initialized, and all blocks from FPM2 525 // should be 0 initialized (since we requested the main FPM, not the alt FPM) 526 for (int I = 0; I < 4; ++I) { 527 EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF)); 528 EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0)); 529 } 530 531 ::memset(MsfBuffer.data(), 0, MsfBuffer.size()); 532 FpmStream = 533 WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true); 534 // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4 535 // blocks. This translates to 1 FPM block. 536 EXPECT_EQ(2048u, FpmStream->getLength()); 537 EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size()); 538 EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]); 539 // All blocks from FPM2 should be 1 initialized, and all blocks from FPM1 540 // should be 0 initialized (since we requested the alt FPM, not the main FPM) 541 for (int I = 0; I < 4; ++I) { 542 EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0)); 543 EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF)); 544 } 545 } 546 547 } // end anonymous namespace 548