[clang] [llvm] [llvm][vfs] Allow root directory remap (PR #83766)

via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 3 21:48:37 PST 2024


https://github.com/yelleyee created https://github.com/llvm/llvm-project/pull/83766

    Add a new feature allowing root(/) directory remap by breaking the
    assumption that remap root must be a directory.
    Now the config below will be allowed.

    Directory-remap config of root(/) is not allowed in previous impl.
    Config list below will cause assertion failure in
    `uniqueOverlayTree`.

```json
    'name': '/',
    'type': 'directory-remap',
    'external-contents': '/xxxx/xxx'
```

Assertion failed stack is attached below:
```
clang -cc1 -ferror-limit 19 -fcolor-diagnostics -o /dev/null -disable-free -emit-obj -x c a.c -tune-cpu generic -target-cpu x86-64 -triple x86_64-unknown-linux-gnu -resource-dir ///MY_ROOT///Source/llvm-project/build/lib/clang/18 -isystem ///MY_ROOT///Source/llvm-project/build/lib/clang/18/include -isystem /usr/local/include -isystem /usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu17 -fmath-errno -fno-implicit-modules -pic-level 2 -pic-is-pie -fgnuc-version=4.2.1 -ffp-contract=on -fno-experimental-relative-c++-abi-vtables -fno-file-reproducible -O0 -fdebug-compilation-dir=///MY_ROOT_1///gitWorkSpace/test -fcoverage-compilation-dir=///MY_ROOT_1///gitWorkSpace/test -faddrsig -mrelax-all -debugger-tuning=gdb -funwind-tables=2 -mconstructor-aliases -clear-ast-before-backend -main-file-name a.c -mframe-pointer=all -fdiagnostics-hotness-threshold=0 -fdiagnostics-misexpect-tolerance=0 -D __GCC_HAVE_DWARF2_CFI_ASM=1 -ivfsoverlay vfs.yaml
clang: ///MY_ROOT///llvm-project/llvm/lib/Support/VirtualFileSystem.cpp:1749: void llvm::vfs::RedirectingFileSystemParser::uniqueOverlayTree(llvm::vfs::RedirectingFileSystem*, llvm::vfs::RedirectingFileSystem::Entry*, llvm::vfs::RedirectingFileSystem::Entry*): Assertion `NewParentE && "Parent entry must exist"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: clang -cc1 -ferror-limit 19 -fcolor-diagnostics -o /dev/null -disable-free -emit-obj -x c a.c -tune-cpu generic -target-cpu x86-64 -triple x86_64-unknown-linux-gnu -resource-dir ///MY_ROOT///Source/llvm-project/build/lib/clang/18 -isystem ///MY_ROOT///Source/llvm-project/build/lib/clang/18/include -isystem /usr/local/include -isystem /usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu17 -fmath-errno -fno-implicit-modules -pic-level 2 -pic-is-pie -fgnuc-version=4.2.1 -ffp-contract=on -fno-experimental-relative-c++-abi-vtables -fno-file-reproducible -O0 -fdebug-compilation-dir=///MY_ROOT_1///gitWorkSpace/test -fcoverage-compilation-dir=///MY_ROOT_1///gitWorkSpace/test -faddrsig -mrelax-all -debugger-tuning=gdb -funwind-tables=2 -mconstructor-aliases -clear-ast-before-backend -main-file-name a.c -mframe-pointer=all -fdiagnostics-hotness-threshold=0 -fdiagnostics-misexpect-tolerance=0 -D __GCC_HAVE_DWARF2_CFI_ASM=1 -ivfsoverlay vfs.yaml
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  libLLVMSupport.so.16       0x00007f3786891a7c llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 82
1  libLLVMSupport.so.16       0x00007f3786891e47
2  libLLVMSupport.so.16       0x00007f378688f72a llvm::sys::RunSignalHandlers() + 159
3  libLLVMSupport.so.16       0x00007f37868913b0
4  libc.so.6                  0x00007f378606f090
5  libc.so.6                  0x00007f378606f00b gsignal + 203
6  libc.so.6                  0x00007f378604e859 abort + 299
7  libc.so.6                  0x00007f378604e729
8  libc.so.6                  0x00007f378605ffd6
9  libLLVMSupport.so.16       0x00007f37868320d2
10 libLLVMSupport.so.16       0x00007f3786834be3
11 libLLVMSupport.so.16       0x00007f3786822f00 llvm::vfs::RedirectingFileSystem::create(std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer>>, void (*)(llvm::SMDiagnostic const&, void*), llvm::StringRef, void*, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) + 994
12 libLLVMSupport.so.16       0x00007f3786825b06 llvm::vfs::getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer>>, void (*)(llvm::SMDiagnostic const&, void*), llvm::StringRef, void*, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) + 169
13 libclangFrontend.so.16     0x00007f378c6145c0 clang::createVFSFromOverlayFiles(llvm::ArrayRef<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, clang::DiagnosticsEngine&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) + 520
14 libclangFrontend.so.16     0x00007f378c614392 clang::createVFSFromCompilerInvocation(clang::CompilerInvocation const&, clang::DiagnosticsEngine&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) + 138
15 libclangFrontend.so.16     0x00007f378c6142e1 clang::createVFSFromCompilerInvocation(clang::CompilerInvocation const&, clang::DiagnosticsEngine&) + 75
16 libclangFrontend.so.16     0x00007f378c56f6b9 clang::CompilerInstance::createFileManager(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) + 175
17 libclangFrontend.so.16     0x00007f378c661b99 clang::FrontendAction::BeginSourceFile(clang::CompilerInstance&, clang::FrontendInputFile const&) + 4027
18 libclangFrontend.so.16     0x00007f378c5738f9 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 919
19 libclangFrontendTool.so.16 0x00007f379224adb6 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 937
20 clang                      0x0000557f7ebde56b cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 1679
21 clang                      0x0000557f7ebcb4ba
22 clang                      0x0000557f7ebcbc8c clang_main(int, char**) + 1442
23 clang                      0x0000557f7ec01ff5 main + 36
24 libc.so.6                  0x00007f3786050083 __libc_start_main + 243
25 clang                      0x0000557f7ebc99ce _start + 46
[1]    116965 abort      clang -cc1 -ferror-limit 19 -fcolor-diagnostics -o /dev/null -disable-free  -

```




>From bd783b0b7c82f9da5b24364cdbb9f6d5953013f1 Mon Sep 17 00:00:00 2001
From: yelleyee <feelyeling at gmail.com>
Date: Mon, 4 Mar 2024 05:32:13 +0000
Subject: [PATCH] [llvm][vfs] Allow root directory remap

    Add a new feature allowing root(/) directory remap by breaking the
    assumption that remap root must be a directory.
    Now the config below will be allowed.

    Directory-remap config of root(/) is not allowed in previous impl.
    Config list below will cause assertion failure in
    `uniqueOverlayTree`.

    'name': '/',
    'type': 'directory-remap',
    'external-contents': '/xxxx/xxx'
---
 clang/test/VFS/Inputs/system-root-remap.yaml  | 12 ++++++
 clang/test/VFS/system-root-remap.c            | 14 +++++++
 llvm/lib/Support/VirtualFileSystem.cpp        | 18 ++++++++
 .../Support/VirtualFileSystemTest.cpp         | 42 +++++++++++++++++++
 4 files changed, 86 insertions(+)
 create mode 100644 clang/test/VFS/Inputs/system-root-remap.yaml
 create mode 100644 clang/test/VFS/system-root-remap.c

diff --git a/clang/test/VFS/Inputs/system-root-remap.yaml b/clang/test/VFS/Inputs/system-root-remap.yaml
new file mode 100644
index 00000000000000..43d25fcc952236
--- /dev/null
+++ b/clang/test/VFS/Inputs/system-root-remap.yaml
@@ -0,0 +1,12 @@
+{
+  'version': 0,
+  'use-external-names': false,
+  'redirecting-with': 'redirect-only'
+  'roots': [
+    {
+      'name': '/',
+      'type': 'directory-remap',
+      'external-contents': 'EXTERNAL_DIR'
+    }
+  ]
+}
diff --git a/clang/test/VFS/system-root-remap.c b/clang/test/VFS/system-root-remap.c
new file mode 100644
index 00000000000000..f4168b75f29909
--- /dev/null
+++ b/clang/test/VFS/system-root-remap.c
@@ -0,0 +1,14 @@
+// RUN: mkdir -p %t
+// RUN: cd %t
+// RUN: sed -e "s at INPUT_DIR@%{/S:regex_replacement}/Inputs at g" -e "s at EXTERNAL_DIR@%{/t:regex_replacement}@g" %S/Inputs/system-root-remap.yaml  > %t.yaml
+// RUN: mkdir -p %t%t
+// RUN: cp %S/Inputs/actual_header.h %t%t/not_real.h
+// RUN: mkdir -p %t%S
+// RUN: cp %s %t%S
+// RUN: %clang_cc1 -Werror -I . -vfsoverlay %t.yaml -fsyntax-only -working-directory=%t %s
+
+#include "not_real.h"
+
+void foo(void) {
+  bar();
+}
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 051dd2a67d120f..1e18cbced9effd 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -1747,6 +1747,10 @@ class llvm::vfs::RedirectingFileSystemParser {
   void uniqueOverlayTree(RedirectingFileSystem *FS,
                          RedirectingFileSystem::Entry *SrcE,
                          RedirectingFileSystem::Entry *NewParentE = nullptr) {
+    if (NewParentE) {
+      assert(NewParentE->getKind() == RedirectingFileSystem::EK_Directory &&
+             "NewParentE must be a directory entry or nullptr");
+    }
     StringRef Name = SrcE->getName();
     switch (SrcE->getKind()) {
     case RedirectingFileSystem::EK_Directory: {
@@ -1756,12 +1760,26 @@ class llvm::vfs::RedirectingFileSystemParser {
       // is parsed. This only leads to redundant walks, ignore it.
       if (!Name.empty())
         NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
+      if (NewParentE->getKind() != RedirectingFileSystem::EK_Directory) {
+        // Found non directory entry, no need to generate the left nodes.
+        break;
+      }
       for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
            llvm::make_range(DE->contents_begin(), DE->contents_end()))
         uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
       break;
     }
     case RedirectingFileSystem::EK_DirectoryRemap: {
+      // Root DirectoryRemap:
+      // name: "/"
+      // external-name: "xxxx"
+      if (!NewParentE) {
+        auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
+        FS->Roots.push_back(
+            std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
+                Name, DR->getExternalContentsPath(), DR->getUseName()));
+        break;
+      }
       assert(NewParentE && "Parent entry must exist");
       auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
       auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index d4abbb4345873c..0a77d8b13eca0e 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -1715,6 +1715,48 @@ TEST_F(VFSFromYAMLTest, MappedRoot) {
   EXPECT_EQ(0, NumDiagnostics);
 }
 
+TEST_F(VFSFromYAMLTest, MappedSysRoot) {
+  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+  Lower->addDirectory("//root/foo/bar");
+  Lower->addRegularFile("//root/foo/bar/a");
+  IntrusiveRefCntPtr<vfs::FileSystem> FS =
+      getFromYAMLString("{ 'roots': [\n"
+                        "{\n"
+                        "  'type': 'directory-remap',\n"
+                        "  'name': '/',\n"
+                        "  'external-contents': '//root/foo/bar'\n"
+                        "}\n"
+                        "]\n"
+                        "}",
+                        Lower);
+  ASSERT_NE(FS.get(), nullptr);
+
+  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+      new vfs::OverlayFileSystem(Lower));
+  O->pushOverlay(FS);
+
+  // file
+  ErrorOr<vfs::Status> S = O->status("/a");
+  ASSERT_FALSE(S.getError());
+  EXPECT_EQ("//root/foo/bar/a", S->getName());
+  EXPECT_TRUE(S->ExposesExternalVFSPath);
+
+  ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
+  EXPECT_EQ("//root/foo/bar/a", SLower->getName());
+  EXPECT_TRUE(S->equivalent(*SLower));
+  EXPECT_FALSE(SLower->ExposesExternalVFSPath);
+
+  // file after opening
+  auto OpenedF = O->openFileForRead("/a");
+  ASSERT_FALSE(OpenedF.getError());
+  auto OpenedS = (*OpenedF)->status();
+  ASSERT_FALSE(OpenedS.getError());
+  EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
+  EXPECT_TRUE(OpenedS->ExposesExternalVFSPath);
+
+  EXPECT_EQ(0, NumDiagnostics);
+}
+
 TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlay) {
   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
   Lower->addDirectory("//root/foo");



More information about the cfe-commits mailing list