[clang][Lexer] Fix crash/assert clang::HeaderSearch::search_dir_nth
authorDmitry Polukhin <dmitry.polukhin@gmail.com>
Wed, 15 Mar 2023 17:45:07 +0000 (10:45 -0700)
committerDmitry Polukhin <dmitry.polukhin@gmail.com>
Thu, 16 Mar 2023 09:19:11 +0000 (02:19 -0700)
The issue was introduced in D135801. When there are only header maps in the SearchDirs,
the out of bounds value is assigned to FirstNonHeaderMapSearchDirIdx.

Test Plan: check-clang

Differential Revision: https://reviews.llvm.org/D146156

clang/lib/Lex/HeaderSearch.cpp
clang/test/Preprocessor/Inputs/header-search-crash/foo.hmap.json [new file with mode: 0644]
clang/test/Preprocessor/header-search-crash.c [new file with mode: 0644]

index 074c147ba3c54edddb1f340431ff8002acb518cd..5a7357a5ada43effce1c6d18e0a58f2f8e74bfbc 100644 (file)
@@ -378,15 +378,17 @@ void HeaderSearch::indexInitialHeaderMaps() {
   llvm::StringMap<unsigned, llvm::BumpPtrAllocator> Index(SearchDirs.size());
 
   // Iterate over all filename keys and associate them with the index i.
-  unsigned i = 0;
-  for (; i != SearchDirs.size(); ++i) {
+  for (unsigned i = 0; i != SearchDirs.size(); ++i) {
     auto &Dir = SearchDirs[i];
 
     // We're concerned with only the initial contiguous run of header
     // maps within SearchDirs, which can be 99% of SearchDirs when
     // SearchDirs.size() is ~10000.
-    if (!Dir.isHeaderMap())
+    if (!Dir.isHeaderMap()) {
+      SearchDirHeaderMapIndex = std::move(Index);
+      FirstNonHeaderMapSearchDirIdx = i;
       break;
+    }
 
     // Give earlier keys precedence over identical later keys.
     auto Callback = [&](StringRef Filename) {
@@ -394,9 +396,6 @@ void HeaderSearch::indexInitialHeaderMaps() {
     };
     Dir.getHeaderMap()->forEachKey(Callback);
   }
-
-  SearchDirHeaderMapIndex = std::move(Index);
-  FirstNonHeaderMapSearchDirIdx = i;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1929,7 +1928,7 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
     llvm::StringRef File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
     bool *IsSystem) {
   using namespace llvm::sys;
-  
+
   llvm::SmallString<32> FilePath = File;
   // remove_dots switches to backslashes on windows as a side-effect!
   // We always want to suggest forward slashes for includes.
diff --git a/clang/test/Preprocessor/Inputs/header-search-crash/foo.hmap.json b/clang/test/Preprocessor/Inputs/header-search-crash/foo.hmap.json
new file mode 100644 (file)
index 0000000..ccfd911
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "mappings" :
+    {
+     "Foo.h" : "Foo/Foo.h"
+    }
+}
diff --git a/clang/test/Preprocessor/header-search-crash.c b/clang/test/Preprocessor/header-search-crash.c
new file mode 100644 (file)
index 0000000..8c04216
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %hmaptool write %S/Inputs/header-search-crash/foo.hmap.json %t/foo.hmap
+// RUN: %clang -cc1 -E %s -I %t/foo.hmap -verify
+
+#include "MissingHeader.h" // expected-error {{'MissingHeader.h' file not found}}