xref: /llvm-project/clang/unittests/Lex/HeaderMapTest.cpp (revision 108e41d962463ea1cb956d1a929692a5b49c0a80)
1 //===- unittests/Lex/HeaderMapTest.cpp - HeaderMap tests ----------===//
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 "HeaderMapTestUtils.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "gtest/gtest.h"
12 #include <type_traits>
13 
14 using namespace clang;
15 using namespace llvm;
16 using namespace clang::test;
17 
18 namespace {
19 
TEST(HeaderMapTest,checkHeaderEmpty)20 TEST(HeaderMapTest, checkHeaderEmpty) {
21   bool NeedsSwap;
22   ASSERT_FALSE(HeaderMapImpl::checkHeader(
23       *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
24   ASSERT_FALSE(HeaderMapImpl::checkHeader(
25       *MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
26 }
27 
TEST(HeaderMapTest,checkHeaderMagic)28 TEST(HeaderMapTest, checkHeaderMagic) {
29   HMapFileMock<1, 1> File;
30   File.init();
31   File.Header.Magic = 0;
32   bool NeedsSwap;
33   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
34 }
35 
TEST(HeaderMapTest,checkHeaderReserved)36 TEST(HeaderMapTest, checkHeaderReserved) {
37   HMapFileMock<1, 1> File;
38   File.init();
39   File.Header.Reserved = 1;
40   bool NeedsSwap;
41   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
42 }
43 
TEST(HeaderMapTest,checkHeaderVersion)44 TEST(HeaderMapTest, checkHeaderVersion) {
45   HMapFileMock<1, 1> File;
46   File.init();
47   ++File.Header.Version;
48   bool NeedsSwap;
49   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
50 }
51 
TEST(HeaderMapTest,checkHeaderValidButEmpty)52 TEST(HeaderMapTest, checkHeaderValidButEmpty) {
53   HMapFileMock<1, 1> File;
54   File.init();
55   bool NeedsSwap;
56   ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
57   ASSERT_FALSE(NeedsSwap);
58 
59   File.swapBytes();
60   ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
61   ASSERT_TRUE(NeedsSwap);
62 }
63 
TEST(HeaderMapTest,checkHeader3Buckets)64 TEST(HeaderMapTest, checkHeader3Buckets) {
65   HMapFileMock<3, 1> File;
66   ASSERT_EQ(3 * sizeof(HMapBucket), sizeof(File.Buckets));
67 
68   File.init();
69   bool NeedsSwap;
70   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
71 }
72 
TEST(HeaderMapTest,checkHeader0Buckets)73 TEST(HeaderMapTest, checkHeader0Buckets) {
74   // Create with 1 bucket to avoid 0-sized arrays.
75   HMapFileMock<1, 1> File;
76   File.init();
77   File.Header.NumBuckets = 0;
78   bool NeedsSwap;
79   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
80 }
81 
TEST(HeaderMapTest,checkHeaderNotEnoughBuckets)82 TEST(HeaderMapTest, checkHeaderNotEnoughBuckets) {
83   HMapFileMock<1, 1> File;
84   File.init();
85   File.Header.NumBuckets = 8;
86   bool NeedsSwap;
87   ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
88 }
89 
TEST(HeaderMapTest,lookupFilename)90 TEST(HeaderMapTest, lookupFilename) {
91   typedef HMapFileMock<2, 7> FileTy;
92   FileTy File;
93   File.init();
94 
95   HMapFileMockMaker<FileTy> Maker(File);
96   auto a = Maker.addString("a");
97   auto b = Maker.addString("b");
98   auto c = Maker.addString("c");
99   Maker.addBucket("a", a, b, c);
100 
101   bool NeedsSwap;
102   ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
103   ASSERT_FALSE(NeedsSwap);
104   HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
105 
106   SmallString<8> DestPath;
107   ASSERT_EQ("bc", Map.lookupFilename("a", DestPath));
108 }
109 
110 template <class FileTy, class PaddingTy> struct PaddedFile {
111   FileTy File;
112   PaddingTy Padding;
113 };
114 
TEST(HeaderMapTest,lookupFilenameTruncatedSuffix)115 TEST(HeaderMapTest, lookupFilenameTruncatedSuffix) {
116   typedef HMapFileMock<2, 64 - sizeof(HMapHeader) - 2 * sizeof(HMapBucket)>
117       FileTy;
118   static_assert(std::is_standard_layout_v<FileTy>, "Expected standard layout");
119   static_assert(sizeof(FileTy) == 64, "check the math");
120   PaddedFile<FileTy, uint64_t> P;
121   auto &File = P.File;
122   auto &Padding = P.Padding;
123   File.init();
124 
125   HMapFileMockMaker<FileTy> Maker(File);
126   auto a = Maker.addString("a");
127   auto b = Maker.addString("b");
128   auto c = Maker.addString("c");
129   Maker.addBucket("a", a, b, c);
130 
131   // Add 'x' characters to cause an overflow into Padding.
132   ASSERT_EQ('c', File.Bytes[5]);
133   for (unsigned I = 6; I < sizeof(File.Bytes); ++I) {
134     ASSERT_EQ(0, File.Bytes[I]);
135     File.Bytes[I] = 'x';
136   }
137   Padding = 0xffffffff; // Padding won't stop it either.
138 
139   bool NeedsSwap;
140   ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
141   ASSERT_FALSE(NeedsSwap);
142   HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
143 
144   // The string for "c" runs to the end of File.  Check that the suffix
145   // ("cxxxx...") is detected as truncated, and an empty string is returned.
146   SmallString<24> DestPath;
147   ASSERT_EQ("", Map.lookupFilename("a", DestPath));
148 }
149 
TEST(HeaderMapTest,lookupFilenameTruncatedPrefix)150 TEST(HeaderMapTest, lookupFilenameTruncatedPrefix) {
151   typedef HMapFileMock<2, 64 - sizeof(HMapHeader) - 2 * sizeof(HMapBucket)>
152       FileTy;
153   static_assert(std::is_standard_layout_v<FileTy>, "Expected standard layout");
154   static_assert(sizeof(FileTy) == 64, "check the math");
155   PaddedFile<FileTy, uint64_t> P;
156   auto &File = P.File;
157   auto &Padding = P.Padding;
158   File.init();
159 
160   HMapFileMockMaker<FileTy> Maker(File);
161   auto a = Maker.addString("a");
162   auto c = Maker.addString("c");
163   auto b = Maker.addString("b"); // Store the prefix last.
164   Maker.addBucket("a", a, b, c);
165 
166   // Add 'x' characters to cause an overflow into Padding.
167   ASSERT_EQ('b', File.Bytes[5]);
168   for (unsigned I = 6; I < sizeof(File.Bytes); ++I) {
169     ASSERT_EQ(0, File.Bytes[I]);
170     File.Bytes[I] = 'x';
171   }
172   Padding = 0xffffffff; // Padding won't stop it either.
173 
174   bool NeedsSwap;
175   ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
176   ASSERT_FALSE(NeedsSwap);
177   HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
178 
179   // The string for "b" runs to the end of File.  Check that the prefix
180   // ("bxxxx...") is detected as truncated, and an empty string is returned.
181   SmallString<24> DestPath;
182   ASSERT_EQ("", Map.lookupFilename("a", DestPath));
183 }
184 
185 } // end namespace
186