bruno created this revision.
bruno added reviewers: rsmith, benlangmuir, klimek.
bruno added subscribers: aprantl, dexonsmith, cfe-commits.

The reproducer script (generated by the crash reproducer) invokes clang
and tries to rebuild modules using the headers in the .cache/vfs
directory. Depending on the order that modules are constructed it is
possible that there's a mismatch between the directory that a module was
constructed and the path that it was found:

fatal error: module '_Builtin_stddef_max_align_t' was built in directory
'/Users/bruno/Dev/install/clang/bin/../lib/clang/<ver>/include'
but now resides in directory
'/<path_to>.cache/vfs/Users/bruno/Dev/install/clang/lib/clang/<ver>/include'

This happens because getFile() can leak the original path depending on
the way it's accessed. This seems to be known issue and one that demands
a lot of work to get rid of, according to:

  [cfe-dev] Module maps, __FILE__ and lazy stat'ing of header
  http://lists.llvm.org/pipermail/cfe-dev/2014-July/038273.html

I tried a couple of fixes to the issue but this is the less invasive I
could come up with. This fixes the issue by first looking into modules
by using virtual dir paths instead of the real ones. Let me know if
there's a better solution or whether I'm missing something.

With this change on Darwin we are able to simulate a crash for a simple
application using "Foundation/Foundation.h" (which relies on a bunch of
different frameworks and headers) and successfully rebuild all the
modules by relying solely at the VFS overlay.

http://reviews.llvm.org/D18849

Files:
  lib/Lex/HeaderSearch.cpp
  test/Modules/Inputs/crash-recovery/Users/bar/a.h
  test/Modules/Inputs/crash-recovery/Users/bar/bar.h
  test/Modules/Inputs/crash-recovery/Users/bar/module.modulemap
  test/Modules/Inputs/crash-recovery/Users/foo/foo.h
  test/Modules/Inputs/crash-recovery/Users/foo/module.modulemap
  test/Modules/crash-vfs-module-redefinition.m

Index: test/Modules/crash-vfs-module-redefinition.m
===================================================================
--- /dev/null
+++ test/Modules/crash-vfs-module-redefinition.m
@@ -0,0 +1,38 @@
+// REQUIRES: crash-recovery, system-darwin, shell
+
+// FIXME: This XFAIL is cargo-culted from crash-report.c. Do we need it?
+// XFAIL: mingw32
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/i %t/m %t
+
+// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \
+// RUN: %clang -fsyntax-only -nostdinc %s \
+// RUN:	    -I %S/Inputs/crash-recovery/Users/bar \
+// RUN:	    -I %S/Inputs/crash-recovery/Users -isysroot %/t/i/ \
+// RUN:     -fmodules -fmodules-cache-path=%t/m/ 2>&1 | FileCheck %s
+
+// RUN: FileCheck --check-prefix=CHECKSRC %s -input-file %t/crash-vfs-*.m
+// RUN: FileCheck --check-prefix=CHECKSH %s -input-file %t/crash-vfs-*.sh
+
+#include <foo/foo.h>
+
+// CHECK: Preprocessed source(s) and associated run script(s) are located at:
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
+
+// CHECKSRC: @import foo;
+
+// CHECKSH: # Crash reproducer
+// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
+// CHECKSH-NEXT: # Original command: {{.*$}}
+// CHECKSH-NEXT: "-cc1"
+// CHECKSH: "-resource-dir"
+// CHECKSH: "-isysroot" "{{[^"]*}}/i/"
+// CHECKSH: "crash-vfs-{{[^ ]*}}.m"
+// CHECKSH: "-ivfsoverlay" "crash-vfs-{{[^ ]*}}.cache/vfs/vfs.yaml"
+// CHECKSH: "-fmodules-cache-path=crash-vfs-{{[^ ]*}}.cache/modules"
+
+// RUN: cd %t
+// RUN: chmod 755 crash-vfs-*.sh
+// RUN: ./crash-vfs-*.sh
Index: test/Modules/Inputs/crash-recovery/Users/foo/module.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/crash-recovery/Users/foo/module.modulemap
@@ -0,0 +1,3 @@
+module foo [system] [extern_c] {
+  header "foo.h"
+}
Index: test/Modules/Inputs/crash-recovery/Users/foo/foo.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/crash-recovery/Users/foo/foo.h
@@ -0,0 +1 @@
+#include <a.h>
Index: test/Modules/Inputs/crash-recovery/Users/bar/module.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/crash-recovery/Users/bar/module.modulemap
@@ -0,0 +1,3 @@
+module bar [system] [extern_c] {
+  header "bar.h"
+}
Index: test/Modules/Inputs/crash-recovery/Users/bar/bar.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/crash-recovery/Users/bar/bar.h
@@ -0,0 +1,6 @@
+#ifndef __CLANG_MAX_ALIGN_T_DEFINED
+#define __CLANG_MAX_ALIGN_T_DEFINED
+
+typedef long double max_align_t;
+
+#endif
Index: test/Modules/Inputs/crash-recovery/Users/bar/a.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/crash-recovery/Users/bar/a.h
@@ -0,0 +1,6 @@
+#ifndef _BAR_H
+#define _BAR_H
+
+#include "bar.h"
+
+#endif
Index: lib/Lex/HeaderSearch.cpp
===================================================================
--- lib/Lex/HeaderSearch.cpp
+++ lib/Lex/HeaderSearch.cpp
@@ -1147,10 +1147,36 @@
 bool HeaderSearch::findUsableModuleForHeader(
     const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
+  using namespace llvm::sys;
   if (File && SuggestedModule) {
+    // FIXME: This is a workaround on a limitation: the file manager leaks
+    // original paths for virtual file requests. This leads to modules being
+    // inconsistently built with virtual and searched through real paths, or
+    // vice-versa, which ends up in module relocation errors. Fix that by
+    // trying to find the module map through the virtual one first. Since
+    // real paths that go through the VFS are canonicalized to do not contain
+    // path traversal components, take that into account.
+    SmallVector<std::string, 2> FilePaths;
+
+    StringRef FileName = File->getName();
+    SmallString<256> RootName = StringRef(Root->getName());
+    path::remove_dots(RootName, true/*remove_dot_dot*/);
+    auto Pos = FileName.find(RootName);
+    if (path::is_absolute(FileName) && Pos != StringRef::npos && Pos > 0) {
+      StringRef Suffix = FileName.drop_front(Pos + RootName.str().size());
+      SmallString<256> NewFileName = StringRef(Root->getName());
+      path::append(NewFileName, Suffix);
+      FilePaths.push_back(NewFileName.str());
+    }
+    FilePaths.push_back(FileName.str());
+
     // If there is a module that corresponds to this header, suggest it.
-    hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
-    *SuggestedModule = findModuleForHeader(File);
+    for (auto &F : FilePaths) {
+      hasModuleMap(F, Root, IsSystemHeaderDir);
+      *SuggestedModule = findModuleForHeader(File);
+      if (SuggestedModule)
+        break;
+    }
   }
   return true;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to