]> granicus.if.org Git - clang/commitdiff
libclang: Put clang_reparseTranslationUnit inside a crash recovery context.
authorDaniel Dunbar <daniel@zuster.org>
Wed, 18 Aug 2010 23:09:31 +0000 (23:09 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Wed, 18 Aug 2010 23:09:31 +0000 (23:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111451 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/ASTUnit.h
test/Index/Inputs/crash-recovery-reparse-remap.c [new file with mode: 0644]
test/Index/crash-recovery-reparse.c [new file with mode: 0644]
tools/libclang/CIndex.cpp

index c05fee1fc876b957f2c4156376cfa57e42058b55..6e67aafb4c9b63d4f7f5ce5316ac023fb3158220 100644 (file)
@@ -273,7 +273,11 @@ private:
   /// This is meant to avoid thrashing during reparsing, by not allowing the
   /// code-completion cache to be updated on every reparse.
   unsigned CacheCodeCompletionCoolDown;
-  
+
+  /// \brief Bit used by CIndex to mark when a translation unit may be in an
+  /// inconsistent state, and is not safe to free.
+  unsigned UnsafeToFree : 1;
+
   /// \brief Cache any "global" code-completion results, so that we can avoid
   /// recomputing them with each completion.
   void CacheCodeCompletionResults();
@@ -329,6 +333,9 @@ public:
 
   bool isMainFileAST() const { return MainFileIsAST; }
 
+  bool isUnsafeToFree() const { return UnsafeToFree; }
+  void setUnsafeToFree(bool Value) { UnsafeToFree = Value; }
+
   const Diagnostic &getDiagnostics() const { return *Diagnostics; }
   Diagnostic &getDiagnostics()             { return *Diagnostics; }
   
diff --git a/test/Index/Inputs/crash-recovery-reparse-remap.c b/test/Index/Inputs/crash-recovery-reparse-remap.c
new file mode 100644 (file)
index 0000000..8a7707a
--- /dev/null
@@ -0,0 +1,3 @@
+#warning parsing remapped file
+
+#pragma clang __debug crash
diff --git a/test/Index/crash-recovery-reparse.c b/test/Index/crash-recovery-reparse.c
new file mode 100644 (file)
index 0000000..0697576
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: env CINDEXTEST_EDITING=1 \
+// RUN:   not c-index-test -test-load-source-reparse 1 local \
+// RUN:   -remap-file="%s;%S/Inputs/crash-recovery-reparse-remap.c" \
+// RUN:   %s 2> %t.err
+// RUN: FileCheck < %t.err -check-prefix=CHECK-REPARSE-SOURCE-CRASH %s
+// CHECK-REPARSE-SOURCE-CRASH: Unable to reparse translation unit
+//
+// XFAIL: win32
+
+#warning parsing original file
index 829873e74fe220fde416ffa2288f4cd7004867cc..fb238df81c021735b43b6c04c5cfe1acf7c488e3 100644 (file)
@@ -1510,20 +1510,39 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
 }
 
 void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
-  if (CTUnit)
+  if (CTUnit) {
+    // If the translation unit has been marked as unsafe to free, just discard
+    // it.
+    if (static_cast<ASTUnit *>(CTUnit)->isUnsafeToFree())
+      return;
+
     delete static_cast<ASTUnit *>(CTUnit);
+  }
 }
 
 unsigned clang_defaultReparseOptions(CXTranslationUnit TU) {
   return CXReparse_None;
 }
 
-int clang_reparseTranslationUnit(CXTranslationUnit TU,
-                                 unsigned num_unsaved_files,
-                                 struct CXUnsavedFile *unsaved_files,
-                                 unsigned options) {
+struct ReparseTranslationUnitInfo {
+  CXTranslationUnit TU;
+  unsigned num_unsaved_files;
+  struct CXUnsavedFile *unsaved_files;
+  unsigned options;
+  int result;
+};
+void clang_reparseTranslationUnit_Impl(void *UserData) {
+  ReparseTranslationUnitInfo *RTUI =
+    static_cast<ReparseTranslationUnitInfo*>(UserData);
+  CXTranslationUnit TU = RTUI->TU;
+  unsigned num_unsaved_files = RTUI->num_unsaved_files;
+  struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files;
+  unsigned options = RTUI->options;
+  (void) options;
+  RTUI->result = 1;
+
   if (!TU)
-    return 1;
+    return;
   
   llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
   for (unsigned I = 0; I != num_unsaved_files; ++I) {
@@ -1534,9 +1553,27 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
                                            Buffer));
   }
   
-  return static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(),
-                                             RemappedFiles.size())? 1 : 0;
+  if (!static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(),
+                                           RemappedFiles.size()))
+      RTUI->result = 0;
 }
+int clang_reparseTranslationUnit(CXTranslationUnit TU,
+                                 unsigned num_unsaved_files,
+                                 struct CXUnsavedFile *unsaved_files,
+                                 unsigned options) {
+  ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files,
+                                      options, 0 };
+  llvm::CrashRecoveryContext CRC;
+
+  if (!CRC.RunSafely(clang_reparseTranslationUnit_Impl, &RTUI)) {
+    // FIXME: Find a way to report the crash.
+    static_cast<ASTUnit *>(TU)->setUnsafeToFree(true);
+    return 1;
+  }
+
+  return RTUI.result;
+}
+
 
 CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
   if (!CTUnit)