Mercurial > hg > CbC > CbC_llvm
comparison clang-tools-extra/clangd/unittests/SerializationTests.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | 0572611fdcc8 |
children | c4bab56944e8 |
comparison
equal
deleted
inserted
replaced
220:42394fc6a535 | 221:79ff65ed7e25 |
---|---|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 // | 6 // |
7 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
8 | 8 |
9 #include "Headers.h" | 9 #include "Headers.h" |
10 #include "RIFF.h" | |
10 #include "index/Index.h" | 11 #include "index/Index.h" |
11 #include "index/Serialization.h" | 12 #include "index/Serialization.h" |
13 #include "support/Logger.h" | |
12 #include "clang/Tooling/CompilationDatabase.h" | 14 #include "clang/Tooling/CompilationDatabase.h" |
15 #include "llvm/ADT/ScopeExit.h" | |
16 #include "llvm/ADT/StringExtras.h" | |
17 #include "llvm/Support/Compression.h" | |
18 #include "llvm/Support/Error.h" | |
13 #include "llvm/Support/ScopedPrinter.h" | 19 #include "llvm/Support/ScopedPrinter.h" |
14 #include "gmock/gmock.h" | 20 #include "gmock/gmock.h" |
15 #include "gtest/gtest.h" | 21 #include "gtest/gtest.h" |
16 | 22 #ifdef LLVM_ON_UNIX |
17 using ::testing::_; | 23 #include <sys/resource.h> |
18 using ::testing::AllOf; | 24 #endif |
25 | |
19 using ::testing::ElementsAre; | 26 using ::testing::ElementsAre; |
20 using ::testing::Pair; | 27 using ::testing::Pair; |
21 using ::testing::UnorderedElementsAre; | 28 using ::testing::UnorderedElementsAre; |
22 using ::testing::UnorderedElementsAreArray; | 29 using ::testing::UnorderedElementsAreArray; |
23 | 30 |
295 EXPECT_NE(SerializedCmd.Filename, Cmd.Filename); | 302 EXPECT_NE(SerializedCmd.Filename, Cmd.Filename); |
296 EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic); | 303 EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic); |
297 EXPECT_NE(SerializedCmd.Output, Cmd.Output); | 304 EXPECT_NE(SerializedCmd.Output, Cmd.Output); |
298 } | 305 } |
299 } | 306 } |
307 | |
308 // rlimit is part of POSIX. | |
309 // ASan uses a lot of address space, so we can't apply strict limits. | |
310 #if LLVM_ON_UNIX && !LLVM_ADDRESS_SANITIZER_BUILD | |
311 class ScopedMemoryLimit { | |
312 struct rlimit OriginalLimit; | |
313 bool Succeeded = false; | |
314 | |
315 public: | |
316 ScopedMemoryLimit(rlim_t Bytes) { | |
317 if (!getrlimit(RLIMIT_AS, &OriginalLimit)) { | |
318 struct rlimit NewLimit = OriginalLimit; | |
319 NewLimit.rlim_cur = Bytes; | |
320 Succeeded = !setrlimit(RLIMIT_AS, &NewLimit); | |
321 } | |
322 if (!Succeeded) | |
323 log("Failed to set rlimit"); | |
324 } | |
325 | |
326 ~ScopedMemoryLimit() { | |
327 if (Succeeded) | |
328 setrlimit(RLIMIT_AS, &OriginalLimit); | |
329 } | |
330 }; | |
331 #else | |
332 class ScopedMemoryLimit { | |
333 public: | |
334 ScopedMemoryLimit(unsigned Bytes) { log("rlimit unsupported"); } | |
335 }; | |
336 #endif | |
337 | |
338 // Test that our deserialization detects invalid array sizes without allocating. | |
339 // If this detection fails, the test should allocate a huge array and crash. | |
340 TEST(SerializationTest, NoCrashOnBadArraySize) { | |
341 // This test is tricky because we need to construct a subtly invalid file. | |
342 // First, create a valid serialized file. | |
343 auto In = readIndexFile(YAML); | |
344 ASSERT_FALSE(!In) << In.takeError(); | |
345 IndexFileOut Out(*In); | |
346 Out.Format = IndexFileFormat::RIFF; | |
347 std::string Serialized = llvm::to_string(Out); | |
348 | |
349 // Low-level parse it again and find the `srcs` chunk we're going to corrupt. | |
350 auto Parsed = riff::readFile(Serialized); | |
351 ASSERT_FALSE(!Parsed) << Parsed.takeError(); | |
352 auto Srcs = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) { | |
353 return C.ID == riff::fourCC("srcs"); | |
354 }); | |
355 ASSERT_NE(Srcs, Parsed->Chunks.end()); | |
356 | |
357 // Srcs consists of a sequence of IncludeGraphNodes. In our case, just one. | |
358 // The node has: | |
359 // - 1 byte: flags (1) | |
360 // - varint(stringID): URI | |
361 // - 8 byte: file digest | |
362 // - varint: DirectIncludes.length | |
363 // - repeated varint(stringID): DirectIncludes | |
364 // We want to set DirectIncludes.length to a huge number. | |
365 // The offset isn't trivial to find, so we use the file digest. | |
366 std::string FileDigest = llvm::fromHex("EED8F5EAF25C453C"); | |
367 unsigned Pos = Srcs->Data.find_first_of(FileDigest); | |
368 ASSERT_NE(Pos, StringRef::npos) << "Couldn't locate file digest"; | |
369 Pos += FileDigest.size(); | |
370 | |
371 // Varints are little-endian base-128 numbers, where the top-bit of each byte | |
372 // indicates whether there are more. ffffffff0f -> 0xffffffff. | |
373 std::string CorruptSrcs = | |
374 (Srcs->Data.take_front(Pos) + llvm::fromHex("ffffffff0f") + | |
375 "some_random_garbage") | |
376 .str(); | |
377 Srcs->Data = CorruptSrcs; | |
378 | |
379 // Try to crash rather than hang on large allocation. | |
380 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB | |
381 | |
382 std::string CorruptFile = llvm::to_string(*Parsed); | |
383 auto CorruptParsed = readIndexFile(CorruptFile); | |
384 ASSERT_TRUE(!CorruptParsed); | |
385 EXPECT_EQ(llvm::toString(CorruptParsed.takeError()), | |
386 "malformed or truncated include uri"); | |
387 } | |
388 | |
389 // Check we detect invalid string table size size without allocating it first. | |
390 // If this detection fails, the test should allocate a huge array and crash. | |
391 TEST(SerializationTest, NoCrashOnBadStringTableSize) { | |
392 if (!llvm::zlib::isAvailable()) { | |
393 log("skipping test, no zlib"); | |
394 return; | |
395 } | |
396 | |
397 // First, create a valid serialized file. | |
398 auto In = readIndexFile(YAML); | |
399 ASSERT_FALSE(!In) << In.takeError(); | |
400 IndexFileOut Out(*In); | |
401 Out.Format = IndexFileFormat::RIFF; | |
402 std::string Serialized = llvm::to_string(Out); | |
403 | |
404 // Low-level parse it again, we're going to replace the `stri` chunk. | |
405 auto Parsed = riff::readFile(Serialized); | |
406 ASSERT_FALSE(!Parsed) << Parsed.takeError(); | |
407 auto Stri = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) { | |
408 return C.ID == riff::fourCC("stri"); | |
409 }); | |
410 ASSERT_NE(Stri, Parsed->Chunks.end()); | |
411 | |
412 // stri consists of an 8 byte uncompressed-size, and then compressed data. | |
413 // We'll claim our small amount of data expands to 4GB | |
414 std::string CorruptStri = | |
415 (llvm::fromHex("ffffffff") + Stri->Data.drop_front(4)).str(); | |
416 Stri->Data = CorruptStri; | |
417 std::string FileDigest = llvm::fromHex("EED8F5EAF25C453C"); | |
418 | |
419 // Try to crash rather than hang on large allocation. | |
420 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB | |
421 | |
422 std::string CorruptFile = llvm::to_string(*Parsed); | |
423 auto CorruptParsed = readIndexFile(CorruptFile); | |
424 ASSERT_TRUE(!CorruptParsed); | |
425 EXPECT_THAT(llvm::toString(CorruptParsed.takeError()), | |
426 testing::HasSubstr("bytes is implausible")); | |
427 } | |
428 | |
300 } // namespace | 429 } // namespace |
301 } // namespace clangd | 430 } // namespace clangd |
302 } // namespace clang | 431 } // namespace clang |