diff --git a/Makefile b/Makefile index 91a99c887..731e96fc4 100644 --- a/Makefile +++ b/Makefile @@ -640,7 +640,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/clangimport.h lib/color.h l test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclass.o test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/redirect.h test/testsuite.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/redirect.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testcmdlineparser.o test/testcmdlineparser.cpp test/testcondition.o: test/testcondition.cpp externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/check.h lib/checkcondition.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index c25ba7c80..5873051be 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -242,11 +242,13 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->addEnabled("information"); } - else if (std::strncmp(argv[i], "--clang", 7) == 0) { + else if (std::strcmp(argv[i], "--clang") == 0) { mSettings->clang = true; - if (std::strncmp(argv[i], "--clang=", 8) == 0) { - mSettings->clangExecutable = argv[i] + 8; - } + } + + else if (std::strncmp(argv[i], "--clang=", 8) == 0) { + mSettings->clang = true; + mSettings->clangExecutable = argv[i] + 8; } else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) { @@ -339,14 +341,19 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } // Exception handling inside cppcheck client - else if (std::strcmp(argv[i], "--exception-handling") == 0) + else if (std::strcmp(argv[i], "--exception-handling") == 0) { mSettings->exceptionHandling = true; + } - // TODO: only applied with Signal handling i.e. Linux + // Exception handling inside cppcheck client else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) { + const std::string exceptionOutfilename = argv[i] + 21; + if (exceptionOutfilename != "stderr" && exceptionOutfilename != "stdout") { + printError("invalid '--exception-handling' argument"); + return false; + } mSettings->exceptionHandling = true; - const std::string exceptionOutfilename = &(argv[i][21]); - CppCheckExecutor::setExceptionOutput((exceptionOutfilename=="stderr") ? stderr : stdout); + CppCheckExecutor::setExceptionOutput((exceptionOutfilename == "stderr") ? stderr : stdout); } // Filter errors diff --git a/cli/cppcheckexecutorseh.cpp b/cli/cppcheckexecutorseh.cpp index b0d3a1425..7f571bd53 100644 --- a/cli/cppcheckexecutorseh.cpp +++ b/cli/cppcheckexecutorseh.cpp @@ -165,9 +165,8 @@ namespace { /* * Any evaluation of the exception needs to be done here! */ - int filterException(int code, PEXCEPTION_POINTERS ex) + int filterException(FILE *outputFile, int code, PEXCEPTION_POINTERS ex) { - FILE *outputFile = stdout; fputs("Internal error: ", outputFile); switch (ex->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: @@ -256,11 +255,10 @@ namespace { */ int check_wrapper_seh(CppCheckExecutor& executor, int (CppCheckExecutor::*f)(CppCheck&), CppCheck& cppcheck) { - FILE *outputFile = stdout; + FILE *outputFile = CppCheckExecutor::getExceptionOutput(); __try { return (&executor->*f)(cppcheck); - } __except (filterException(GetExceptionCode(), GetExceptionInformation())) { - // reporting to stdout may not be helpful within a GUI application... + } __except (filterException(outputFile, GetExceptionCode(), GetExceptionInformation())) { fputs("Please report this to the cppcheck developers!\n", outputFile); return -1; } diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 31fe87859..4a0d94ff2 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -40,5 +40,17 @@ if (MSVC AND DISABLE_CRTDBG_MAP_ALLOC) add_definitions(-DDISABLE_CRTDBG_MAP_ALLOC) endif() +if (NO_UNIX_SIGNAL_HANDLING) + add_definitions(-DNO_UNIX_SIGNAL_HANDLING) +endif() + +if (NO_UNIX_BACKTRACE_SUPPORT) + add_definitions(-DNO_UNIX_BACKTRACE_SUPPORT) +endif() + +if (NO_WINDOWS_SEH) + add_definitions(-DNO_WINDOWS_SEH) +endif() + file(TO_CMAKE_PATH ${FILESDIR} _filesdir) add_definitions(-DFILESDIR="${_filesdir}") diff --git a/cmake/options.cmake b/cmake/options.cmake index 90c94a0d4..1f8f7342c 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -45,7 +45,11 @@ option(USE_BUNDLED_TINYXML2 "Usage of bundled tinyxml2 library" option(CPPCHK_GLIBCXX_DEBUG "Usage of _GLIBCXX_DEBUG in Debug build" ON) option(USE_THREADS "Usage of threads instead of fork() for -j" OFF) option(USE_BOOST "Usage of Boost" OFF) + option(DISABLE_CRTDBG_MAP_ALLOC "Disable usage of Visual Studio C++ memory leak detection in Debug build" OFF) +option(NO_UNIX_SIGNAL_HANDLING "Disable usage of Unix Signal Handling" OFF) +option(NO_UNIX_BACKTRACE_SUPPORT "Disable usage of Unix Backtrace support" OFF) +option(NO_WINDOWS_SEH "Disable usage of Windows SEH" OFF) if (CMAKE_VERSION VERSION_EQUAL "3.16" OR CMAKE_VERSION VERSION_GREATER "3.16") set(CMAKE_DISABLE_PRECOMPILE_HEADERS Off CACHE BOOL "Disable precompiled headers") diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index 5aada969a..ad5d0c383 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -28,6 +28,11 @@ message( STATUS ) message( STATUS "USE_MATCHCOMPILER = ${USE_MATCHCOMPILER}" ) message( STATUS "USE_MATCHCOMPILER_OPT = ${USE_MATCHCOMPILER_OPT}" ) message( STATUS ) +message( STATUS "DISABLE_CRTDBG_MAP_ALLOC = ${DISABLE_CRTDBG_MAP_ALLOC}") +message( STATUS "NO_UNIX_SIGNAL_HANDLING = ${NO_UNIX_SIGNAL_HANDLING}") +message( STATUS "NO_UNIX_BACKTRACE_SUPPORT = ${NO_UNIX_BACKTRACE_SUPPORT}") +message( STATUS "NO_WINDOWS_SEH = ${NO_WINDOWS_SEH}") +message( STATUS ) if(NOT DEFINED BUILD_SHARED_LIBS) message( STATUS "BUILD_SHARED_LIBS = OFF" ) else() diff --git a/lib/config.h b/lib/config.h index 60daf8e38..05d8b8238 100644 --- a/lib/config.h +++ b/lib/config.h @@ -131,7 +131,7 @@ static const std::string emptyString; #define SUPPRESS_FLOAT_EQUAL_WARNING(...) __VA_ARGS__ #endif -#if defined(_WIN32) && defined(_MSC_VER) +#if !defined(NO_WINDOWS_SEH) && defined(_WIN32) && defined(_MSC_VER) #define USE_WINDOWS_SEH #endif diff --git a/releasenotes.txt b/releasenotes.txt index 39cc6f070..0f8ce1bb0 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -2,3 +2,5 @@ release notes for cppcheck-2.9 - restored check for negative allocation (new[]) and negative VLA sizes from cppcheck 1.87 (LCppC backport) - replaced hardcoded check for pipe() buffer size by library configuration option (LCppC backport) +- on Windows the callstack is now being written to the output specific via "--exception-handling" +- make it possible to disable the various exception handling parts via the CMake options "NO_UNIX_SIGNAL_HANDLING", "NO_UNIX_BACKTRACE_SUPPORT" and "NO_WINDOWS_SEH" \ No newline at end of file diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 12229f59a..efaa0b4d1 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -17,6 +17,7 @@ */ #include "cmdlineparser.h" +#include "cppcheckexecutor.h" #include "errortypes.h" #include "platform.h" #include "redirect.h" @@ -131,6 +132,14 @@ private: TEST_CASE(errorlistverbose1); TEST_CASE(errorlistverbose2); TEST_CASE(ignorepathsnopath); + TEST_CASE(exceptionhandling); + TEST_CASE(exceptionhandling2); + TEST_CASE(exceptionhandling3); + TEST_CASE(exceptionhandlingInvalid); + TEST_CASE(exceptionhandlingInvalid2); + TEST_CASE(clang); + TEST_CASE(clang2); + TEST_CASE(clangInvalid); // TODO // Disabling these tests since they use relative paths to the @@ -965,6 +974,77 @@ private: ASSERT_EQUALS(0, parser.getIgnoredPaths().size()); } + void exceptionhandling() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling"}; + settings.exceptionHandling = false; + CppCheckExecutor::setExceptionOutput(stderr); + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(settings.exceptionHandling); + ASSERT_EQUALS(stderr, CppCheckExecutor::getExceptionOutput()); + } + + void exceptionhandling2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling=stderr"}; + settings.exceptionHandling = false; + CppCheckExecutor::setExceptionOutput(stdout); + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(settings.exceptionHandling); + ASSERT_EQUALS(stderr, CppCheckExecutor::getExceptionOutput()); + } + + void exceptionhandling3() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling=stdout"}; + settings.exceptionHandling = false; + CppCheckExecutor::setExceptionOutput(stderr); + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(settings.exceptionHandling); + ASSERT_EQUALS(stdout, CppCheckExecutor::getExceptionOutput()); + } + + void exceptionhandlingInvalid() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling=exfile"}; + ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: invalid '--exception-handling' argument\n", GET_REDIRECT_OUTPUT); + } + + void exceptionhandlingInvalid2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling-foo"}; + ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exception-handling-foo\".\n", GET_REDIRECT_OUTPUT); + } + + void clang() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--clang"}; + settings.clang = false; + settings.clangExecutable = "exe"; + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(settings.clang); + ASSERT_EQUALS("exe", settings.clangExecutable); + } + + void clang2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--clang=clang-14"}; + settings.clang = false; + settings.clangExecutable = ""; + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT(settings.clang); + ASSERT_EQUALS("clang-14", settings.clangExecutable); + } + + void clangInvalid() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--clang-foo"}; + ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--clang-foo\".\n", GET_REDIRECT_OUTPUT); + } + /* void ignorepaths1() { REDIRECT;