blob: b93423de7accaf01a2f01e0fb54259fa4d1fd8bc [file] [log] [blame]
Zachary Turner90b8b8d2016-05-31 22:41:52 +00001//===- llvm/unittest/DebugInfo/PDB/MappedBlockStreamTest.cpp --------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <unordered_map>
11
12#include "llvm/DebugInfo/CodeView/StreamReader.h"
13#include "llvm/DebugInfo/CodeView/StreamRef.h"
14#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
15#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
16#include "gtest/gtest.h"
17
18using namespace llvm;
19using namespace llvm::codeview;
20using namespace llvm::pdb;
21
22namespace {
23
24#define EXPECT_NO_ERROR(Err) \
25 { \
26 auto E = std::move(Err); \
27 EXPECT_FALSE(static_cast<bool>(E)); \
28 if (E) \
29 consumeError(std::move(E)); \
30 }
31
32#define EXPECT_ERROR(Err) \
33 { \
34 auto E = std::move(Err); \
35 EXPECT_TRUE(static_cast<bool>(E)); \
36 if (E) \
37 consumeError(std::move(E)); \
38 }
39
NAKAMURA Takumi47d1e372016-06-01 14:26:54 +000040static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
41static const char DataAry[] = {'A', 'B', 'C', 'F', 'E',
42 'D', 'G', 'H', 'I', 'J'};
43
Zachary Turner90b8b8d2016-05-31 22:41:52 +000044class DiscontiguousFile : public IPDBFile {
45public:
46 DiscontiguousFile()
NAKAMURA Takumi47d1e372016-06-01 14:26:54 +000047 : Blocks(&BlocksAry[0], &BlocksAry[10]), Data(&DataAry[0], &DataAry[10]) {
48 }
Zachary Turner90b8b8d2016-05-31 22:41:52 +000049
50 virtual uint32_t getBlockSize() const override { return 1; }
51 virtual uint32_t getBlockCount() const override { return 10; }
52 virtual uint32_t getNumStreams() const override { return 1; }
53 virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const override {
54 return getBlockCount() * getBlockSize();
55 }
56 virtual ArrayRef<uint32_t>
57 getStreamBlockList(uint32_t StreamIndex) const override {
58 if (StreamIndex != 0)
59 return ArrayRef<uint32_t>();
60 return Blocks;
61 }
62 virtual StringRef getBlockData(uint32_t BlockIndex,
63 uint32_t NumBytes) const override {
64 return StringRef(&Data[BlockIndex], NumBytes);
65 }
66
67private:
68 std::vector<uint32_t> Blocks;
69 std::vector<char> Data;
70};
71
72// Tests that a read which is entirely contained within a single block works
73// and does not allocate.
74TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
75 DiscontiguousFile F;
76 MappedBlockStream S(0, F);
77 StreamReader R(S);
78 StringRef Str;
79 EXPECT_NO_ERROR(R.readFixedString(Str, 1));
80 EXPECT_EQ(Str, StringRef("A"));
81 EXPECT_EQ(0, S.getNumBytesCopied());
82}
83
84// Tests that a read which outputs into a full destination buffer works and
85// does not fail due to the length of the output buffer.
86TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
87 DiscontiguousFile F;
88 MappedBlockStream S(0, F);
89 StreamReader R(S);
90 StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
91 EXPECT_NO_ERROR(R.readFixedString(Str, 1));
92 EXPECT_EQ(Str, StringRef("A"));
93 EXPECT_EQ(0, S.getNumBytesCopied());
94}
95
96// Tests that a read which crosses a block boundary, but where the subsequent
97// blocks are still contiguous in memory to the previous block works and does
98// not allocate memory.
99TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
100 DiscontiguousFile F;
101 MappedBlockStream S(0, F);
102 StreamReader R(S);
103 StringRef Str;
104 EXPECT_NO_ERROR(R.readFixedString(Str, 2));
105 EXPECT_EQ(Str, StringRef("AB"));
106 EXPECT_EQ(0, S.getNumBytesCopied());
107
108 R.setOffset(6);
109 EXPECT_NO_ERROR(R.readFixedString(Str, 4));
110 EXPECT_EQ(Str, StringRef("GHIJ"));
111 EXPECT_EQ(0, S.getNumBytesCopied());
112}
113
114// Tests that a read which crosses a block boundary and cannot be referenced
115// contiguously works and allocates only the precise amount of bytes
116// requested.
117TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
118 DiscontiguousFile F;
119 MappedBlockStream S(0, F);
120 StreamReader R(S);
121 StringRef Str;
122 EXPECT_NO_ERROR(R.readFixedString(Str, 10));
123 EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
124 EXPECT_EQ(10, S.getNumBytesCopied());
125}
126
127// Test that an out of bounds read which doesn't cross a block boundary
128// fails and allocates no memory.
129TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
130 DiscontiguousFile F;
131 MappedBlockStream S(0, F);
132 StreamReader R(S);
133 StringRef Str;
134
135 R.setOffset(10);
136 EXPECT_ERROR(R.readFixedString(Str, 1));
137 EXPECT_EQ(0, S.getNumBytesCopied());
138}
139
140// Test that an out of bounds read which crosses a contiguous block boundary
141// fails and allocates no memory.
142TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
143 DiscontiguousFile F;
144 MappedBlockStream S(0, F);
145 StreamReader R(S);
146 StringRef Str;
147
148 R.setOffset(6);
149 EXPECT_ERROR(R.readFixedString(Str, 5));
150 EXPECT_EQ(0, S.getNumBytesCopied());
151}
152
153// Test that an out of bounds read which crosses a discontiguous block
154// boundary fails and allocates no memory.
155TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
156 DiscontiguousFile F;
157 MappedBlockStream S(0, F);
158 StreamReader R(S);
159 StringRef Str;
160
161 EXPECT_ERROR(R.readFixedString(Str, 11));
162 EXPECT_EQ(0, S.getNumBytesCopied());
163}
164
165} // end anonymous namespace