From: Jan Korous Date: Thu, 12 Sep 2019 22:55:55 +0000 (+0000) Subject: [libclang] Expose abort()-ing LLVM fatal error handler X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9541955239ac8960895fe26e44913d5dbc3be222;p=clang [libclang] Expose abort()-ing LLVM fatal error handler Differential Revision: https://reviews.llvm.org/D66775 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371787 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/FatalErrorHandler.h b/include/clang-c/FatalErrorHandler.h new file mode 100644 index 0000000000..74c9a8fe98 --- /dev/null +++ b/include/clang-c/FatalErrorHandler.h @@ -0,0 +1,33 @@ +/*===-- clang-c/FatalErrorHandler.h - Fatal Error Handling --------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_FATAL_ERROR_HANDLER_H +#define LLVM_CLANG_C_FATAL_ERROR_HANDLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Installs error handler that prints error message to stderr and calls abort(). + * Replaces currently installed error handler (if any). + */ +void clang_install_aborting_llvm_fatal_error_handler(); + +/** + * Removes currently installed error handler (if any). + * If no error handler is intalled, the default strategy is to print error + * message to stderr and call exit(1). + */ +void clang_uninstall_llvm_fatal_error_handler(); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 5ea2d5e4a8..5e77808a74 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -20,6 +20,7 @@ #include "CXTranslationUnit.h" #include "CXType.h" #include "CursorVisitor.h" +#include "clang-c/FatalErrorHandler.h" #include "clang/AST/Attr.h" #include "clang/AST/Mangle.h" #include "clang/AST/StmtVisitor.h" @@ -3243,18 +3244,10 @@ RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, // Misc. API hooks. //===----------------------------------------------------------------------===// -static void fatal_error_handler(void *user_data, const std::string& reason, - bool gen_crash_diag) { - // Write the result out to stderr avoiding errs() because raw_ostreams can - // call report_fatal_error. - fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str()); - ::abort(); -} - namespace { struct RegisterFatalErrorHandler { RegisterFatalErrorHandler() { - llvm::install_fatal_error_handler(fatal_error_handler, nullptr); + clang_install_aborting_llvm_fatal_error_handler(); } }; } diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 9fd24ff463..bd0c945a5e 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -19,6 +19,7 @@ set(SOURCES CXString.cpp CXType.cpp Indexing.cpp + FatalErrorHandler.cpp ADDITIONAL_HEADERS CIndexDiagnostic.h @@ -43,6 +44,7 @@ set(LIBS clangSema clangSerialization clangTooling + LLVMSupport ) if (CLANG_ENABLE_ARCMT) diff --git a/tools/libclang/FatalErrorHandler.cpp b/tools/libclang/FatalErrorHandler.cpp new file mode 100644 index 0000000000..e9a0d41bab --- /dev/null +++ b/tools/libclang/FatalErrorHandler.cpp @@ -0,0 +1,28 @@ +/*===-- clang-c/FatalErrorHandler.cpp - Fatal Error Handling ------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "clang-c/FatalErrorHandler.h" +#include "llvm/Support/ErrorHandling.h" + +static void aborting_fatal_error_handler(void *, const std::string &reason, + bool) { + // Write the result out to stderr avoiding errs() because raw_ostreams can + // call report_fatal_error. + fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str()); + ::abort(); +} + +void clang_install_aborting_llvm_fatal_error_handler() { + llvm::remove_fatal_error_handler(); + llvm::install_fatal_error_handler(aborting_fatal_error_handler, nullptr); +} + +void clang_uninstall_llvm_fatal_error_handler() { + llvm::remove_fatal_error_handler(); +} diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 3c76090d64..9408c02083 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -379,3 +379,5 @@ clang_EvalResult_dispose clang_PrintingPolicy_getProperty clang_PrintingPolicy_setProperty clang_PrintingPolicy_dispose +clang_install_aborting_llvm_fatal_error_handler +clang_uninstall_llvm_fatal_error_handler diff --git a/unittests/libclang/CMakeLists.txt b/unittests/libclang/CMakeLists.txt index 36f6089787..b3644a0e71 100644 --- a/unittests/libclang/CMakeLists.txt +++ b/unittests/libclang/CMakeLists.txt @@ -6,3 +6,5 @@ target_link_libraries(libclangTests PRIVATE libclang ) + +add_subdirectory(CrashTests) diff --git a/unittests/libclang/CrashTests/CMakeLists.txt b/unittests/libclang/CrashTests/CMakeLists.txt new file mode 100644 index 0000000000..82f0e4c16e --- /dev/null +++ b/unittests/libclang/CrashTests/CMakeLists.txt @@ -0,0 +1,8 @@ +add_clang_unittest(libclangCrashTests + LibclangCrashTest.cpp + ) + +target_link_libraries(libclangCrashTests + PRIVATE + libclang + ) diff --git a/unittests/libclang/CrashTests/LibclangCrashTest.cpp b/unittests/libclang/CrashTests/LibclangCrashTest.cpp new file mode 100644 index 0000000000..821ef849ae --- /dev/null +++ b/unittests/libclang/CrashTests/LibclangCrashTest.cpp @@ -0,0 +1,36 @@ +//===- unittests/libclang/LibclangCrashTest.cpp --- libclang tests --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../TestUtils.h" +#include "clang-c/FatalErrorHandler.h" +#include "gtest/gtest.h" +#include + +TEST_F(LibclangParseTest, InstallAbortingLLVMFatalErrorHandler) { + clang_toggleCrashRecovery(0); + clang_install_aborting_llvm_fatal_error_handler(); + + std::string Main = "main.h"; + WriteFile(Main, "#pragma clang __debug llvm_fatal_error"); + + EXPECT_DEATH(clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, + nullptr, 0, TUFlags), + ""); +} + +TEST_F(LibclangParseTest, UninstallAbortingLLVMFatalErrorHandler) { + clang_toggleCrashRecovery(0); + clang_install_aborting_llvm_fatal_error_handler(); + clang_uninstall_llvm_fatal_error_handler(); + + std::string Main = "main.h"; + WriteFile(Main, "#pragma clang __debug llvm_fatal_error"); + + EXPECT_NO_FATAL_FAILURE(clang_parseTranslationUnit( + Index, Main.c_str(), nullptr, 0, nullptr, 0, TUFlags)); +}