clang-tools 24.0.0git
SerializationTests.cpp
Go to the documentation of this file.
1//===-- SerializationTests.cpp - Binary and YAML serialization unit 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 "FindSymbols.h"
10#include "Headers.h"
11#include "RIFF.h"
12#include "TestIndex.h"
13#include "index/Serialization.h"
14#include "support/Logger.h"
15#include "clang/Tooling/CompilationDatabase.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
18#include "llvm/Support/Compression.h"
19#include "llvm/Support/Error.h"
20#include "llvm/Support/ScopedPrinter.h"
21#include "gmock/gmock.h"
22#include "gtest/gtest.h"
23#ifdef LLVM_ON_UNIX
24#include <sys/resource.h>
25#endif
26
27using ::testing::ElementsAre;
28using ::testing::Pair;
29using ::testing::UnorderedElementsAre;
30using ::testing::UnorderedElementsAreArray;
31
32namespace clang {
33namespace clangd {
34namespace {
35
36const char *YAML = R"(
37---
38!Symbol
39ID: 057557CEBF6E6B2D
40Name: 'Foo1'
41Scope: 'clang::'
42SymInfo:
43 Kind: Function
44 Lang: Cpp
45CanonicalDeclaration:
46 FileURI: file:///path/foo.h
47 Start:
48 Line: 1
49 Column: 0
50 End:
51 Line: 1
52 Column: 1
53Flags: 129
54Tags: 258
55Documentation: 'Foo doc'
56ReturnType: 'int'
57IncludeHeaders:
58 - Header: 'include1'
59 References: 7
60 Directives: [ Include ]
61 - Header: 'include2'
62 References: 3
63 Directives: [ Import ]
64 - Header: 'include3'
65 References: 2
66 Directives: [ Include, Import ]
67 - Header: 'include4'
68 References: 1
69 Directives: [ ]
70...
71---
72!Symbol
73ID: 057557CEBF6E6B2E
74Name: 'Foo2'
75Scope: 'clang::'
76SymInfo:
77 Kind: Function
78 Lang: Cpp
79CanonicalDeclaration:
80 FileURI: file:///path/bar.h
81 Start:
82 Line: 1
83 Column: 0
84 End:
85 Line: 1
86 Column: 1
87Flags: 2
88Signature: '-sig'
89CompletionSnippetSuffix: '-snippet'
90...
91!Refs
92ID: 057557CEBF6E6B2D
93References:
94 - Kind: 4
95 Location:
96 FileURI: file:///path/foo.cc
97 Start:
98 Line: 5
99 Column: 3
100 End:
101 Line: 5
102 Column: 8
103...
104--- !Relations
105Subject:
106 ID: 6481EE7AF2841756
107Predicate: 0
108Object:
109 ID: 6512AEC512EA3A2D
110...
111--- !Cmd
112Directory: 'testdir'
113CommandLine:
114 - 'cmd1'
115 - 'cmd2'
116...
117--- !Source
118URI: 'file:///path/source1.cpp'
119Flags: 1
120Digest: EED8F5EAF25C453C
121DirectIncludes:
122 - 'file:///path/inc1.h'
123 - 'file:///path/inc2.h'
124...
125)";
126
127MATCHER_P(id, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
128MATCHER_P(qName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
129MATCHER_P3(IncludeHeaderWithRefAndDirectives, IncludeHeader, References,
130 SupportedDirectives, "") {
131 return (arg.IncludeHeader == IncludeHeader) &&
132 (arg.References == References) &&
133 (arg.SupportedDirectives == SupportedDirectives);
134}
135
136auto readIndexFile(llvm::StringRef Text) {
138}
139
140TEST(SerializationTest, NoCrashOnEmptyYAML) {
141 EXPECT_TRUE(bool(readIndexFile("")));
142}
143
144TEST(SerializationTest, YAMLConversions) {
145 auto ParsedYAML = readIndexFile(YAML);
146 ASSERT_TRUE(bool(ParsedYAML)) << ParsedYAML.takeError();
147 ASSERT_TRUE(bool(ParsedYAML->Symbols));
148 EXPECT_THAT(
149 *ParsedYAML->Symbols,
150 UnorderedElementsAre(id("057557CEBF6E6B2D"), id("057557CEBF6E6B2E")));
151
152 auto Sym1 = *ParsedYAML->Symbols->find(
153 cantFail(SymbolID::fromStr("057557CEBF6E6B2D")));
154 auto Sym2 = *ParsedYAML->Symbols->find(
155 cantFail(SymbolID::fromStr("057557CEBF6E6B2E")));
156
157 EXPECT_THAT(Sym1, qName("clang::Foo1"));
158 EXPECT_EQ(Sym1.Signature, "");
159 EXPECT_EQ(Sym1.Documentation, "Foo doc");
160 EXPECT_EQ(Sym1.ReturnType, "int");
161 EXPECT_EQ(StringRef(Sym1.CanonicalDeclaration.FileURI), "file:///path/foo.h");
162 EXPECT_EQ(Sym1.Origin, SymbolOrigin::Static);
163 EXPECT_EQ(static_cast<uint8_t>(Sym1.Flags), 129);
164 EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
165 EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
166 // Tags: Deprecated (1<<1=2) | Static (1<<8=256) = 258
167 EXPECT_EQ(Sym1.Tags, 258u);
168 EXPECT_TRUE(Sym1.Tags & toSymbolTagBitmask(SymbolTag::Deprecated));
169 EXPECT_TRUE(Sym1.Tags & toSymbolTagBitmask(SymbolTag::Static));
170 EXPECT_THAT(
171 Sym1.IncludeHeaders,
172 UnorderedElementsAre(
173 IncludeHeaderWithRefAndDirectives("include1", 7u, Symbol::Include),
174 IncludeHeaderWithRefAndDirectives("include2", 3u, Symbol::Import),
175 IncludeHeaderWithRefAndDirectives("include3", 2u,
177 IncludeHeaderWithRefAndDirectives("include4", 1u, Symbol::Invalid)));
178
179 EXPECT_THAT(Sym2, qName("clang::Foo2"));
180 EXPECT_EQ(Sym2.Signature, "-sig");
181 EXPECT_EQ(Sym2.ReturnType, "");
182 EXPECT_EQ(llvm::StringRef(Sym2.CanonicalDeclaration.FileURI),
183 "file:///path/bar.h");
184 EXPECT_FALSE(Sym2.Flags & Symbol::IndexedForCodeCompletion);
185 EXPECT_TRUE(Sym2.Flags & Symbol::Deprecated);
186 EXPECT_EQ(Sym2.Tags, 0u); // no Tags in YAML → default zero
187
188 ASSERT_TRUE(bool(ParsedYAML->Refs));
189 EXPECT_THAT(
190 *ParsedYAML->Refs,
191 UnorderedElementsAre(Pair(cantFail(SymbolID::fromStr("057557CEBF6E6B2D")),
192 ::testing::SizeIs(1))));
193 auto Ref1 = ParsedYAML->Refs->begin()->second.front();
194 EXPECT_EQ(Ref1.Kind, RefKind::Reference);
195 EXPECT_EQ(StringRef(Ref1.Location.FileURI), "file:///path/foo.cc");
196
197 SymbolID Base = cantFail(SymbolID::fromStr("6481EE7AF2841756"));
198 SymbolID Derived = cantFail(SymbolID::fromStr("6512AEC512EA3A2D"));
199 ASSERT_TRUE(bool(ParsedYAML->Relations));
200 EXPECT_THAT(
201 *ParsedYAML->Relations,
202 UnorderedElementsAre(Relation{Base, RelationKind::BaseOf, Derived}));
203
204 ASSERT_TRUE(bool(ParsedYAML->Cmd));
205 auto &Cmd = *ParsedYAML->Cmd;
206 ASSERT_EQ(Cmd.Directory, "testdir");
207 EXPECT_THAT(Cmd.CommandLine, ElementsAre("cmd1", "cmd2"));
208
209 ASSERT_TRUE(bool(ParsedYAML->Sources));
210 const auto *URI = "file:///path/source1.cpp";
211 ASSERT_TRUE(ParsedYAML->Sources->count(URI));
212 auto IGNDeserialized = ParsedYAML->Sources->lookup(URI);
213 EXPECT_EQ(llvm::toHex(IGNDeserialized.Digest), "EED8F5EAF25C453C");
214 EXPECT_THAT(IGNDeserialized.DirectIncludes,
215 ElementsAre("file:///path/inc1.h", "file:///path/inc2.h"));
216 EXPECT_EQ(IGNDeserialized.URI, URI);
217 EXPECT_EQ(IGNDeserialized.Flags, IncludeGraphNode::SourceFlag(1));
218}
219
220std::vector<std::string> yamlFromSymbols(const SymbolSlab &Slab) {
221 std::vector<std::string> Result;
222 for (const auto &Sym : Slab)
223 Result.push_back(toYAML(Sym));
224 return Result;
225}
226std::vector<std::string> yamlFromRefs(const RefSlab &Slab) {
227 std::vector<std::string> Result;
228 for (const auto &Refs : Slab)
229 Result.push_back(toYAML(Refs));
230 return Result;
231}
232
233std::vector<std::string> yamlFromRelations(const RelationSlab &Slab) {
234 std::vector<std::string> Result;
235 for (const auto &Rel : Slab)
236 Result.push_back(toYAML(Rel));
237 return Result;
238}
239
240TEST(SerializationTest, BinaryConversions) {
241 auto In = readIndexFile(YAML);
242 EXPECT_TRUE(bool(In)) << In.takeError();
243
244 // Write to binary format, and parse again.
245 IndexFileOut Out(*In);
246 Out.Format = IndexFileFormat::RIFF;
247 std::string Serialized = llvm::to_string(Out);
248
249 auto In2 = readIndexFile(Serialized);
250 ASSERT_TRUE(bool(In2)) << In2.takeError();
251 ASSERT_TRUE(In2->Symbols);
252 ASSERT_TRUE(In2->Refs);
253 ASSERT_TRUE(In2->Relations);
254
255 // Assert the YAML serializations match, for nice comparisons and diffs.
256 EXPECT_THAT(yamlFromSymbols(*In2->Symbols),
257 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
258 EXPECT_THAT(yamlFromRefs(*In2->Refs),
259 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
260 EXPECT_THAT(yamlFromRelations(*In2->Relations),
261 UnorderedElementsAreArray(yamlFromRelations(*In->Relations)));
262}
263
264// Every SymbolKind must have a YAML spelling, otherwise writing the index
265// produces invalid YAML (or aborts with assertions enabled).
266TEST(SerializationTest, YAMLSymbolKindRoundTrip) {
267 SymbolSlab::Builder Builder;
268 for (unsigned K = static_cast<unsigned>(index::SymbolKind::Unknown);
269 K <= static_cast<unsigned>(index::SymbolKind::Concept); ++K) {
270 std::string Name = "Sym" + std::to_string(K);
271 Symbol Sym = symbol(Name);
272 Sym.SymInfo.Kind = static_cast<index::SymbolKind>(K);
273 Builder.insert(Sym);
274 }
275 SymbolSlab Symbols = std::move(Builder).build();
276
277 IndexFileOut Out;
278 Out.Symbols = &Symbols;
279 Out.Format = IndexFileFormat::YAML;
280
281 auto In = readIndexFile(llvm::to_string(Out));
282 ASSERT_TRUE(bool(In)) << In.takeError();
283 ASSERT_TRUE(In->Symbols);
284 for (const Symbol &Sym : Symbols) {
285 auto It = In->Symbols->find(Sym.ID);
286 ASSERT_NE(It, In->Symbols->end()) << Sym.Name;
287 EXPECT_EQ(It->SymInfo.Kind, Sym.SymInfo.Kind) << Sym.Name;
288 }
289}
290
291TEST(SerializationTest, SrcsTest) {
292 auto In = readIndexFile(YAML);
293 EXPECT_TRUE(bool(In)) << In.takeError();
294
295 std::string TestContent("TestContent");
297 IGN.Digest = digest(TestContent);
298 IGN.DirectIncludes = {"inc1", "inc2"};
299 IGN.URI = "URI";
302 IncludeGraph Sources;
303 Sources[IGN.URI] = IGN;
304 // Write to binary format, and parse again.
305 IndexFileOut Out(*In);
306 Out.Format = IndexFileFormat::RIFF;
307 Out.Sources = &Sources;
308 {
309 std::string Serialized = llvm::to_string(Out);
310
311 auto In = readIndexFile(Serialized);
312 ASSERT_TRUE(bool(In)) << In.takeError();
313 ASSERT_TRUE(In->Symbols);
314 ASSERT_TRUE(In->Refs);
315 ASSERT_TRUE(In->Sources);
316 ASSERT_TRUE(In->Sources->count(IGN.URI));
317 // Assert the YAML serializations match, for nice comparisons and diffs.
318 EXPECT_THAT(yamlFromSymbols(*In->Symbols),
319 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
320 EXPECT_THAT(yamlFromRefs(*In->Refs),
321 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
322 auto IGNDeserialized = In->Sources->lookup(IGN.URI);
323 EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
324 EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
325 EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
326 EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
327 }
328}
329
330// Verify that Symbol::Tags survive a full YAML -> RIFF -> read roundtrip.
331// This exercises both writeSymbol (new Tags field) and readSymbol.
332TEST(SerializationTest, TagsRoundTrip) {
333 // YAML fixture with a single symbol carrying non-zero Tags.
334 // Deprecated (SymbolTag=1) -> bit 1 -> 1<<1 = 2
335 // Static (SymbolTag=8) -> bit 8 -> 1<<8 = 256
336 // Combined: 258
337 const char *TaggedYAML = R"(
338---
339!Symbol
340ID: AABBCCDDEEFF0011
341Name: 'Tagged'
342Scope: 'ns::'
343SymInfo:
344 Kind: Function
345 Lang: Cpp
346CanonicalDeclaration:
347 FileURI: file:///tmp/tagged.h
348 Start:
349 Line: 0
350 Column: 0
351 End:
352 Line: 0
353 Column: 1
354Flags: 1
355Tags: 258
356...
357)";
358 const SymbolID TaggedID = cantFail(SymbolID::fromStr("AABBCCDDEEFF0011"));
359 const SymbolTags ExpectedTags =
362 constexpr unsigned ExpectedTagMask = 258u;
363 EXPECT_EQ(ExpectedTags, ExpectedTagMask); // bitmask sanity check
364
365 // ── Step 1: YAML deserialization ────────────────────────────────────────
366 auto FromYAML = readIndexFile(TaggedYAML);
367 ASSERT_TRUE(bool(FromYAML)) << FromYAML.takeError();
368 ASSERT_TRUE(bool(FromYAML->Symbols));
369 {
370 auto It = FromYAML->Symbols->find(TaggedID);
371 ASSERT_NE(It, FromYAML->Symbols->end())
372 << "symbol not found after YAML parse";
373 EXPECT_EQ(It->Tags, ExpectedTags)
374 << "Tags lost during YAML deserialization";
375 }
376
377 // ── Step 2: RIFF serialization + deserialization ────────────────────────
378 IndexFileOut Out(*FromYAML);
379 Out.Format = IndexFileFormat::RIFF;
380 std::string Serialized = llvm::to_string(Out);
381
382 auto FromRIFF = readIndexFile(Serialized);
383 ASSERT_TRUE(bool(FromRIFF)) << FromRIFF.takeError();
384 ASSERT_TRUE(bool(FromRIFF->Symbols));
385 {
386 auto It = FromRIFF->Symbols->find(TaggedID);
387 ASSERT_NE(It, FromRIFF->Symbols->end())
388 << "symbol not found after RIFF roundtrip";
389 EXPECT_EQ(It->Tags, ExpectedTags) << "Tags lost during RIFF serialization";
390 // Spot-check individual bits
391 EXPECT_TRUE(It->Tags & toSymbolTagBitmask(SymbolTag::Deprecated));
392 EXPECT_TRUE(It->Tags & toSymbolTagBitmask(SymbolTag::Static));
393 EXPECT_FALSE(It->Tags & toSymbolTagBitmask(SymbolTag::Abstract));
394 }
395
396 // ── Step 3: Symbol with Tags=0 must survive too ─────────────────────────
397 const char *UntaggedYAML = R"(
398---
399!Symbol
400ID: 0000000000000001
401Name: 'Untagged'
402Scope: ''
403SymInfo:
404 Kind: Variable
405 Lang: Cpp
406CanonicalDeclaration:
407 FileURI: file:///tmp/untagged.h
408 Start:
409 Line: 0
410 Column: 0
411 End:
412 Line: 0
413 Column: 1
414Flags: 1
415...
416)";
417 auto FromUntaggedYAML = readIndexFile(UntaggedYAML);
418 ASSERT_TRUE(bool(FromUntaggedYAML)) << FromUntaggedYAML.takeError();
419 ASSERT_TRUE(bool(FromUntaggedYAML->Symbols));
420 IndexFileOut Out2(*FromUntaggedYAML);
421 Out2.Format = IndexFileFormat::RIFF;
422 auto FromUntaggedRIFF = readIndexFile(llvm::to_string(Out2));
423 ASSERT_TRUE(bool(FromUntaggedRIFF)) << FromUntaggedRIFF.takeError();
424 ASSERT_TRUE(bool(FromUntaggedRIFF->Symbols));
425 {
426 const SymbolID UntaggedID = cantFail(SymbolID::fromStr("0000000000000001"));
427 auto It = FromUntaggedRIFF->Symbols->find(UntaggedID);
428 ASSERT_NE(It, FromUntaggedRIFF->Symbols->end());
429 EXPECT_EQ(It->Tags, 0u) << "Tags must be zero for untagged symbol";
430 }
431}
432
433TEST(SerializationTest, CmdlTest) {
434 auto In = readIndexFile(YAML);
435 EXPECT_TRUE(bool(In)) << In.takeError();
436
437 tooling::CompileCommand Cmd;
438 Cmd.Directory = "testdir";
439 Cmd.CommandLine.push_back("cmd1");
440 Cmd.CommandLine.push_back("cmd2");
441 Cmd.Filename = "ignored";
442 Cmd.Heuristic = "ignored";
443 Cmd.Output = "ignored";
444
445 IndexFileOut Out(*In);
446 Out.Format = IndexFileFormat::RIFF;
447 Out.Cmd = &Cmd;
448 {
449 std::string Serialized = llvm::to_string(Out);
450
451 auto In = readIndexFile(Serialized);
452 ASSERT_TRUE(bool(In)) << In.takeError();
453 ASSERT_TRUE(In->Cmd);
454
455 const tooling::CompileCommand &SerializedCmd = *In->Cmd;
456 EXPECT_EQ(SerializedCmd.CommandLine, Cmd.CommandLine);
457 EXPECT_EQ(SerializedCmd.Directory, Cmd.Directory);
458 EXPECT_NE(SerializedCmd.Filename, Cmd.Filename);
459 EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic);
460 EXPECT_NE(SerializedCmd.Output, Cmd.Output);
461 }
462}
463
464// rlimit is part of POSIX. RLIMIT_AS does not exist in OpenBSD.
465// Sanitizers use a lot of address space, so we can't apply strict limits.
466#if LLVM_ON_UNIX && defined(RLIMIT_AS) && !LLVM_ADDRESS_SANITIZER_BUILD && \
467 !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_THREAD_SANITIZER_BUILD
468class ScopedMemoryLimit {
469 struct rlimit OriginalLimit;
470 bool Succeeded = false;
471
472public:
473 ScopedMemoryLimit(rlim_t Bytes) {
474 if (!getrlimit(RLIMIT_AS, &OriginalLimit)) {
475 struct rlimit NewLimit = OriginalLimit;
476 NewLimit.rlim_cur = Bytes;
477 Succeeded = !setrlimit(RLIMIT_AS, &NewLimit);
478 }
479 if (!Succeeded)
480 log("Failed to set rlimit");
481 }
482
483 ~ScopedMemoryLimit() {
484 if (Succeeded)
485 setrlimit(RLIMIT_AS, &OriginalLimit);
486 }
487};
488#else
489class ScopedMemoryLimit {
490public:
491 ScopedMemoryLimit(unsigned Bytes) { log("rlimit unsupported"); }
492};
493#endif
494
495// Test that our deserialization detects invalid array sizes without allocating.
496// If this detection fails, the test should allocate a huge array and crash.
497TEST(SerializationTest, NoCrashOnBadArraySize) {
498 // This test is tricky because we need to construct a subtly invalid file.
499 // First, create a valid serialized file.
500 auto In = readIndexFile(YAML);
501 ASSERT_FALSE(!In) << In.takeError();
502 IndexFileOut Out(*In);
503 Out.Format = IndexFileFormat::RIFF;
504 std::string Serialized = llvm::to_string(Out);
505
506 // Low-level parse it again and find the `srcs` chunk we're going to corrupt.
507 auto Parsed = riff::readFile(Serialized);
508 ASSERT_FALSE(!Parsed) << Parsed.takeError();
509 auto Srcs = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) {
510 return C.ID == riff::fourCC("srcs");
511 });
512 ASSERT_NE(Srcs, Parsed->Chunks.end());
513
514 // Srcs consists of a sequence of IncludeGraphNodes. In our case, just one.
515 // The node has:
516 // - 1 byte: flags (1)
517 // - varint(stringID): URI
518 // - 8 byte: file digest
519 // - varint: DirectIncludes.length
520 // - repeated varint(stringID): DirectIncludes
521 // We want to set DirectIncludes.length to a huge number.
522 // The offset isn't trivial to find, so we use the file digest.
523 std::string FileDigest = llvm::fromHex("EED8F5EAF25C453C");
524 unsigned Pos = Srcs->Data.find_first_of(FileDigest);
525 ASSERT_NE(Pos, StringRef::npos) << "Couldn't locate file digest";
526 Pos += FileDigest.size();
527
528 // Varints are little-endian base-128 numbers, where the top-bit of each byte
529 // indicates whether there are more. ffffffff0f -> 0xffffffff.
530 std::string CorruptSrcs =
531 (Srcs->Data.take_front(Pos) + llvm::fromHex("ffffffff0f") +
532 "some_random_garbage")
533 .str();
534 Srcs->Data = CorruptSrcs;
535
536 // Try to crash rather than hang on large allocation.
537 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB
538
539 std::string CorruptFile = llvm::to_string(*Parsed);
540 auto CorruptParsed = readIndexFile(CorruptFile);
541 ASSERT_TRUE(!CorruptParsed);
542 EXPECT_EQ(llvm::toString(CorruptParsed.takeError()),
543 "malformed or truncated include uri");
544}
545
546// Check we detect invalid string table size size without allocating it first.
547// If this detection fails, the test should allocate a huge array and crash.
548TEST(SerializationTest, NoCrashOnBadStringTableSize) {
549 if (!llvm::compression::zlib::isAvailable()) {
550 log("skipping test, no zlib");
551 return;
552 }
553
554 // First, create a valid serialized file.
555 auto In = readIndexFile(YAML);
556 ASSERT_FALSE(!In) << In.takeError();
557 IndexFileOut Out(*In);
558 Out.Format = IndexFileFormat::RIFF;
559 std::string Serialized = llvm::to_string(Out);
560
561 // Low-level parse it again, we're going to replace the `stri` chunk.
562 auto Parsed = riff::readFile(Serialized);
563 ASSERT_FALSE(!Parsed) << Parsed.takeError();
564 auto Stri = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) {
565 return C.ID == riff::fourCC("stri");
566 });
567 ASSERT_NE(Stri, Parsed->Chunks.end());
568
569 // stri consists of an 8 byte uncompressed-size, and then compressed data.
570 // We'll claim our small amount of data expands to 4GB
571 std::string CorruptStri =
572 (llvm::fromHex("ffffffff") + Stri->Data.drop_front(4)).str();
573 Stri->Data = CorruptStri;
574
575 // Try to crash rather than hang on large allocation.
576 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB
577
578 std::string CorruptFile = llvm::to_string(*Parsed);
579 auto CorruptParsed = readIndexFile(CorruptFile);
580 ASSERT_TRUE(!CorruptParsed);
581 EXPECT_THAT(llvm::toString(CorruptParsed.takeError()),
582 testing::HasSubstr("bytes is implausible"));
583}
584
585} // namespace
586} // namespace clangd
587} // namespace clang
An efficient structure of storing large set of symbol references in memory.
Definition Ref.h:111
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition SymbolID.cpp:37
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
Definition Symbol.h:238
An immutable symbol container that stores a set of symbols.
Definition Symbol.h:215
A URI describes the location of a source file.
Definition URI.h:28
llvm::Expected< File > readFile(llvm::StringRef Stream)
Definition RIFF.cpp:48
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
uint32_t SymbolTags
A bitmask type representing symbol tags supported by LSP.
Definition Symbol.h:29
FileDigest digest(llvm::StringRef Content)
MATCHER_P(named, N, "")
SymbolTags toSymbolTagBitmask(const SymbolTag ST)
Converts a single SymbolTag to a bitmask.
TEST(BackgroundQueueTest, Priority)
Symbol symbol(llvm::StringRef QName)
Definition TestIndex.cpp:17
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition Headers.h:103
void log(const char *Fmt, Ts &&... Vals)
Definition Logger.h:67
std::string toYAML(const Symbol &)
std::array< uint8_t, 8 > FileDigest
Definition SourceCode.h:42
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const SymbolSlab * Symbols
Represents a relation between two symbols.
Definition Relation.h:32
Ensure we have enough bits to represent all SymbolTag values.
Definition Symbol.h:49
@ IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
Definition Symbol.h:155
@ Deprecated
Indicates if the symbol is deprecated.
Definition Symbol.h:157
@ Include
#include "header.h"
Definition Symbol.h:107
@ Import
#import "header.h"
Definition Symbol.h:109