From 79acdd94022fb21a0a3c4ee83fc647dd8e84798f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 18 Aug 2010 23:09:31 +0000 Subject: [PATCH] libclang: Put clang_reparseTranslationUnit inside a crash recovery context. llvm-svn: 111451 --- clang/include/clang/Frontend/ASTUnit.h | 9 +++- .../Inputs/crash-recovery-reparse-remap.c | 3 ++ clang/test/Index/crash-recovery-reparse.c | 10 ++++ clang/tools/libclang/CIndex.cpp | 53 ++++++++++++++++--- 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 clang/test/Index/Inputs/crash-recovery-reparse-remap.c create mode 100644 clang/test/Index/crash-recovery-reparse.c diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index c05fee1fc876..6e67aafb4c9b 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -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/clang/test/Index/Inputs/crash-recovery-reparse-remap.c b/clang/test/Index/Inputs/crash-recovery-reparse-remap.c new file mode 100644 index 000000000000..8a7707a59024 --- /dev/null +++ b/clang/test/Index/Inputs/crash-recovery-reparse-remap.c @@ -0,0 +1,3 @@ +#warning parsing remapped file + +#pragma clang __debug crash diff --git a/clang/test/Index/crash-recovery-reparse.c b/clang/test/Index/crash-recovery-reparse.c new file mode 100644 index 000000000000..0697576880f7 --- /dev/null +++ b/clang/test/Index/crash-recovery-reparse.c @@ -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 diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 829873e74fe2..fb238df81c02 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -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(CTUnit)->isUnsafeToFree()) + return; + delete static_cast(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(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 RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { @@ -1534,9 +1553,27 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU, Buffer)); } - return static_cast(TU)->Reparse(RemappedFiles.data(), - RemappedFiles.size())? 1 : 0; + if (!static_cast(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(TU)->setUnsafeToFree(true); + return 1; + } + + return RTUI.result; +} + CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { if (!CTUnit)