summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Langmuir <blangmuir@apple.com>2014-05-19 16:13:45 +0000
committerBen Langmuir <blangmuir@apple.com>2014-05-19 16:13:45 +0000
commitca39214f4e9fddf247e880ef9562865be850fce6 (patch)
tree09bf034f2b8f6e3d07a787f27a4ad644c8d89da6
parentd71b6dfd854f4dbff946ae22a7f4b89cbd22048e (diff)
downloadbcm5719-llvm-ca39214f4e9fddf247e880ef9562865be850fce6.tar.gz
bcm5719-llvm-ca39214f4e9fddf247e880ef9562865be850fce6.zip
Fix use-after-free and spurious error during module load
FileManager::invalidateCache is not safe to call when there may be existing references to the file. What module load failure needs is to refresh so stale stat() info isn't stored. This may be the last user of invalidateCache; I'll take a look and remove it if possible in a future commit. This caused a use-after-free error as well as a spurious error message that a module was "found in both 'X.pcm' and 'X.pcm'" in some cases. llvm-svn: 209138
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp15
-rw-r--r--clang/test/Modules/load-after-failure.m25
2 files changed, 38 insertions, 2 deletions
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 66f18158a69..c3152c0b021 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -152,9 +152,20 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
// Delete the modules and erase them from the various structures.
for (ModuleIterator victim = first; victim != last; ++victim) {
- Modules.erase((*victim)->File);
+ const FileEntry *F = (*victim)->File;
+ Modules.erase(F);
+
+ // Refresh the stat() information for the module file so stale information
+ // doesn't get stored accidentally.
+ vfs::Status UpdatedStat;
+ if (FileMgr.getNoncachedStatValue(F->getName(), UpdatedStat)) {
+ llvm::report_fatal_error(Twine("module file '") + F->getName() +
+ "' removed after it has been used");
+ } else {
+ FileMgr.modifyFileEntry(const_cast<FileEntry *>(F), UpdatedStat.getSize(),
+ UpdatedStat.getLastModificationTime().toEpochTime());
+ }
- FileMgr.invalidateCache((*victim)->File);
if (modMap) {
StringRef ModuleName = (*victim)->ModuleName;
if (Module *mod = modMap->findModule(ModuleName)) {
diff --git a/clang/test/Modules/load-after-failure.m b/clang/test/Modules/load-after-failure.m
new file mode 100644
index 00000000000..f471fd88d50
--- /dev/null
+++ b/clang/test/Modules/load-after-failure.m
@@ -0,0 +1,25 @@
+// REQUIRES: shell
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// RUN: echo '@import B;' > %t/A.h
+// RUN: echo '@import C;' > %t/B.h
+// RUN: echo '@import D;' >> %t/B.h
+// RUN: echo '// C.h' > %t/C.h
+// RUN: echo '// D.h' > %t/D.h
+// RUN: echo 'module A { header "A.h" }' > %t/module.modulemap
+// RUN: echo 'module B { header "B.h" }' >> %t/module.modulemap
+// RUN: echo 'module C { header "C.h" }' >> %t/module.modulemap
+// RUN: echo 'module D { header "D.h" }' >> %t/module.modulemap
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %t %s -verify
+// RUN: echo " " >> %t/D.h
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %t %s -verify
+// expected-no-diagnostics
+
+
+@import C;
+@import A;
+@import C;
+// When compiling A, C will be be loaded then removed when D fails. Ensure
+// this does not cause problems importing C again later.
OpenPOWER on IntegriCloud