MappedBlockStreamTest.cpp 21 KB

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