diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 2a357c793b..d06e9586f2 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -96,6 +96,7 @@ #include #include #include +#include #include #include #include @@ -164,18 +165,6 @@ #include "SafeMode.h" -#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler -# pragma warning( disable : 4535 ) -# if !defined(_DEBUG) && defined(HAVE_SEH) -# define FC_SE_TRANSLATOR -# endif - -# include -# include // VC exception handling -#else // Ansi C/C++ new handler -# include -#endif - #ifdef FC_OS_WIN32 #include #endif @@ -1774,175 +1763,59 @@ void Application::destructObserver() } } -/** freecadNewHandler() - * prints an error message and throws an exception - */ -#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler -int __cdecl freecadNewHandler(size_t size ) +namespace { - // throw an exception - throw Base::MemoryException(); - return 0; -} -#else // Ansi C/C++ new handler -static void freecadNewHandler () +void initExceptions() { - // throw an exception - throw Base::MemoryException(); + // register exception producer types + // NOLINTBEGIN + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + new Base::ExceptionProducer; + // NOLINTEND } -#endif - -#if defined(FC_OS_LINUX) -#include -#include -#include - -#include -#include -#include -#include - -#if HAVE_CONFIG_H -#include -#endif // HAVE_CONFIG_H - -// This function produces a stack backtrace with demangled function & method names. -void printBacktrace(size_t skip=0) -{ -#if defined HAVE_BACKTRACE_SYMBOLS - void *callstack[128]; - size_t nMaxFrames = sizeof(callstack) / sizeof(callstack[0]); - size_t nFrames = backtrace(callstack, nMaxFrames); - char **symbols = backtrace_symbols(callstack, nFrames); - - for (size_t i = skip; i < nFrames; i++) { - char *demangled = nullptr; - int status = -1; - Dl_info info; - if (dladdr(callstack[i], &info) && info.dli_sname && info.dli_fname) { - if (info.dli_sname[0] == '_') { - demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); - } - } - - std::stringstream str; - if (status == 0) { - void* offset = (void*)((char*)callstack[i] - (char*)info.dli_saddr); - str << "#" << (i-skip) << " " << callstack[i] << " in " << demangled << " from " << info.dli_fname << "+" << offset << '\n'; - free(demangled); - } - else { - str << "#" << (i-skip) << " " << symbols[i] << '\n'; - } - - // cannot directly print to cerr when using --write-log - std::cerr << str.str(); - } - - free(symbols); -#else //HAVE_BACKTRACE_SYMBOLS - (void)skip; - std::cerr << "Cannot print the stacktrace because the C runtime library doesn't provide backtrace or backtrace_symbols\n"; -#endif } -#endif - -void segmentation_fault_handler(int sig) -{ -#if defined(FC_OS_LINUX) - (void)sig; - std::cerr << "Program received signal SIGSEGV, Segmentation fault.\n"; - printBacktrace(2); -#if defined(FC_DEBUG) - abort(); -#else - _exit(1); -#endif -#else - switch (sig) { - case SIGSEGV: - std::cerr << "Illegal storage access..." << '\n'; -#if !defined(_DEBUG) - throw Base::AccessViolation("Illegal storage access! Please save your work under a new file name and restart the application!"); -#endif - break; - case SIGABRT: - std::cerr << "Abnormal program termination..." << '\n'; -#if !defined(_DEBUG) - throw Base::AbnormalProgramTermination("Break signal occurred"); -#endif - break; - default: - std::cerr << "Unknown error occurred..." << '\n'; - break; - } -#endif // FC_OS_LINUX -} - -void unhandled_exception_handler() -{ - std::cerr << "Terminating..." << '\n'; -} - -void unexpection_error_handler() -{ - std::cerr << "Unexpected error occurred..." << '\n'; - // try to throw an exception and give the user chance to save their work -#if !defined(_DEBUG) - throw Base::AbnormalProgramTermination("Unexpected error occurred! Please save your work under a new file name and restart the application!"); -#else - terminate(); -#endif -} - -#if defined(FC_SE_TRANSLATOR) // Microsoft compiler -void my_se_translator_filter(unsigned int code, EXCEPTION_POINTERS* pExp) -{ - Q_UNUSED(pExp) - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - throw Base::AccessViolation(); - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - Base::Console().error("SEH exception (%u): Division by zero\n", code); - return; - } - - std::stringstream str; - str << "SEH exception of type: " << code; - // general C++ SEH exception for things we don't need to handle separately.... - throw Base::RuntimeError(str.str()); -} -#endif void Application::init(int argc, char ** argv) { try { - // install our own new handler -#ifdef _MSC_VER // Microsoft compiler - _set_new_handler ( freecadNewHandler ); // Setup new handler - _set_new_mode( 1 ); // Re-route malloc failures to new handler ! -#else // Ansi compiler - std::set_new_handler (freecadNewHandler); // ANSI new handler -#endif - // if an unexpected crash occurs we can install a handler function to - // write some additional information -#if defined (_MSC_VER) // Microsoft compiler - std::signal(SIGSEGV,segmentation_fault_handler); - std::signal(SIGABRT,segmentation_fault_handler); - std::set_terminate(unhandled_exception_handler); - ::set_unexpected(unexpection_error_handler); -#elif defined(FC_OS_LINUX) - std::signal(SIGSEGV,segmentation_fault_handler); -#endif -#if defined(FC_SE_TRANSLATOR) - _set_se_translator(my_se_translator_filter); -#endif + Base::SystemHandler::installNewHandler(); + Base::SystemHandler::installSegfaultHandler(); + initTypes(); initConfig(argc,argv); initApplication(); + initExceptions(); } catch (...) { // force the log to flush diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 79904bb860..26448f0293 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -13,6 +13,10 @@ if(BUILD_TRACY_FRAME_PROFILER) add_definitions(-DBUILD_TRACY_FRAME_PROFILER) endif() +if(FREECAD_RELEASE_SEH) + add_definitions(-DHAVE_SEH) +endif(FREECAD_RELEASE_SEH) + target_include_directories( FreeCADBase PRIVATE @@ -225,6 +229,7 @@ SET(FreeCADBase_CPP_SRCS Stream.cpp Swap.cpp ${SWIG_SRCS} + SystemHandler.cpp Tools.cpp Tools2D.cpp Tools3D.cpp @@ -291,6 +296,7 @@ SET(FreeCADBase_HPP_SRCS Stream.h Swap.h ${SWIG_HEADERS} + SystemHandler.h TimeInfo.h Tools.h Tools2D.h diff --git a/src/Base/SystemHandler.cpp b/src/Base/SystemHandler.cpp new file mode 100644 index 0000000000..64b536a2a8 --- /dev/null +++ b/src/Base/SystemHandler.cpp @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2025 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include +#include + +#include "SystemHandler.h" +#include "Console.h" +#include "Exception.h" + +#ifdef FC_OS_WIN32 +# include +#endif + +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +# pragma warning(disable : 4535) +# if !defined(_DEBUG) && defined(HAVE_SEH) +# define FC_SE_TRANSLATOR +# endif + +# include +# include // VC exception handling +#else // Ansi C/C++ new handler +# include +#endif + +using namespace Base; + +/** freecadNewHandler() + * prints an error message and throws an exception + */ +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +int __cdecl freecadNewHandler(size_t size) +{ + // throw an exception + throw Base::MemoryException(); + return 0; +} +#else // Ansi C/C++ new handler +static void freecadNewHandler() +{ + // throw an exception + throw Base::MemoryException(); +} +#endif + +#if defined(FC_OS_LINUX) +# include +# include +# include +# include + +# include +# include +# include + +# if HAVE_CONFIG_H +# include +# endif // HAVE_CONFIG_H + +// This function produces a stack backtrace with demangled function & method names. +static void printBacktrace([[maybe_unused]] size_t skip = 0) +{ +# if defined HAVE_BACKTRACE_SYMBOLS + void* callstack[128]; + size_t nMaxFrames = sizeof(callstack) / sizeof(callstack[0]); + size_t nFrames = backtrace(callstack, nMaxFrames); + char** symbols = backtrace_symbols(callstack, nFrames); + + for (size_t i = skip; i < nFrames; i++) { + char* demangled = nullptr; + int status = -1; + Dl_info info; + if (dladdr(callstack[i], &info) && info.dli_sname && info.dli_fname) { + if (info.dli_sname[0] == '_') { + demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); + } + } + + std::stringstream str; + if (status == 0) { + void* offset = (void*)((char*)callstack[i] - (char*)info.dli_saddr); + str << "#" << (i - skip) << " " << callstack[i] << " in " << demangled << " from " + << info.dli_fname << "+" << offset << '\n'; + free(demangled); + } + else { + str << "#" << (i - skip) << " " << symbols[i] << '\n'; + } + + // cannot directly print to cerr when using --write-log + std::cerr << str.str(); + } + + free(symbols); +# else // HAVE_BACKTRACE_SYMBOLS + std::cerr << "Cannot print the stacktrace because the C runtime library doesn't provide " + "backtrace or backtrace_symbols\n"; +# endif +} +#endif + +void segmentation_fault_handler([[maybe_unused]] int sig) +{ +#if defined(FC_OS_LINUX) + std::cerr << "Program received signal SIGSEGV, Segmentation fault.\n"; + printBacktrace(2); +# if defined(FC_DEBUG) + abort(); +# else + _exit(1); +# endif +#else + switch (sig) { + case SIGSEGV: + std::cerr << "Illegal storage access..." << '\n'; +# if !defined(_DEBUG) + throw Base::AccessViolation( + "Illegal storage access! Please save your work under a new " + "file name and restart the application!" + ); +# endif + break; + case SIGABRT: + std::cerr << "Abnormal program termination..." << '\n'; +# if !defined(_DEBUG) + throw Base::AbnormalProgramTermination("Break signal occurred"); +# endif + break; + default: + std::cerr << "Unknown error occurred..." << '\n'; + break; + } +#endif // FC_OS_LINUX +} + +#if defined(_MSC_VER) +static void unhandled_exception_handler() +{ + std::cerr << "Terminating..." << '\n'; +} + +static void unexpection_error_handler() +{ + std::cerr << "Unexpected error occurred..." << '\n'; + // try to throw an exception and give the user chance to save their work +# if !defined(_DEBUG) + throw Base::AbnormalProgramTermination( + "Unexpected error occurred! Please save your work under " + "a new file name and restart the application!" + ); +# else + terminate(); +# endif +} +#endif + +#if defined(FC_SE_TRANSLATOR) // Microsoft compiler +void my_se_translator_filter(unsigned int code, EXCEPTION_POINTERS* /*pExp*/) +{ + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + throw Base::AccessViolation(); + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + Base::Console().error("SEH exception (%u): Division by zero\n", code); + return; + } + + std::stringstream str; + str << "SEH exception of type: " << code; + // general C++ SEH exception for things we don't need to handle separately.... + throw Base::RuntimeError(str.str()); +} +#endif + +void SystemHandler::installNewHandler() +{ +#ifdef _MSC_VER // Microsoft compiler + _set_new_handler(freecadNewHandler); // Setup new handler + _set_new_mode(1); // Re-route malloc failures to new handler ! +#else // Ansi compiler + std::set_new_handler(freecadNewHandler); // ANSI new handler +#endif +} + +void SystemHandler::installSegfaultHandler() +{ + // if an unexpected crash occurs we can install a handler function to + // write some additional information +#if defined(_MSC_VER) // Microsoft compiler + std::signal(SIGSEGV, segmentation_fault_handler); + std::signal(SIGABRT, segmentation_fault_handler); + std::set_terminate(unhandled_exception_handler); + ::set_unexpected(unexpection_error_handler); +#elif defined(FC_OS_LINUX) + std::signal(SIGSEGV, segmentation_fault_handler); +#endif +#if defined(FC_SE_TRANSLATOR) + _set_se_translator(my_se_translator_filter); +#endif +} diff --git a/src/Base/SystemHandler.h b/src/Base/SystemHandler.h new file mode 100644 index 0000000000..e67e929b20 --- /dev/null +++ b/src/Base/SystemHandler.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2025 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#pragma once + +#include + +namespace Base +{ + +class BaseExport SystemHandler +{ +public: + static void installNewHandler(); + static void installSegfaultHandler(); +}; + +} // namespace Base diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 1f16b1956f..23b487ff07 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -569,6 +569,8 @@ SET(Part_SRCS PreCompiled.h Services.cpp Services.h + SignalException.cpp + SignalException.h TopoShape.cpp TopoShape.h TopoShapeCache.cpp diff --git a/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp b/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp index 6fcba9efc5..1fdb17ea17 100644 --- a/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp +++ b/src/Mod/Part/App/FCBRepAlgoAPI_BooleanOperation.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include FCBRepAlgoAPI_BooleanOperation::FCBRepAlgoAPI_BooleanOperation() @@ -103,6 +104,7 @@ void FCBRepAlgoAPI_BooleanOperation::Build() void FCBRepAlgoAPI_BooleanOperation::Build(const Message_ProgressRange& progressRange) { + Part::SignalException sig; if (progressRange.UserBreak()) { Standard_ConstructionError::Raise("User aborted"); } diff --git a/src/Mod/Part/App/SignalException.cpp b/src/Mod/Part/App/SignalException.cpp new file mode 100644 index 0000000000..47780bfbcf --- /dev/null +++ b/src/Mod/Part/App/SignalException.cpp @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2025 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "SignalException.h" +#include +#if defined(__GNUC__) && defined(FC_OS_LINUX) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include + +using namespace Part; + +// NOLINTBEGIN(concurrency-mt-unsafe, cppcoreguidelines-pro-type-member-init) +#if defined(__GNUC__) && defined(FC_OS_LINUX) +static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs; // NOLINT + +static void SegvHandler(const int theSignal, siginfo_t* theSigInfo, const Standard_Address /*theContext*/) +{ + std::cerr << "\nStacktrace:" << std::endl; + std::cerr << "SIGSEGV signal raised: " << theSignal << std::endl; + std::cerr << boost::stacktrace::stacktrace() << std::endl; + std::cerr << "\n" << std::endl; + if (theSigInfo != nullptr) { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGSEGV); + sigprocmask(SIG_UNBLOCK, &set, nullptr); + OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump(); + } + exit(SIGSEGV); +} + +static void throw_exc(const int theSignal, siginfo_t* /*theSigInfo*/, const Standard_Address /*theContext*/) +{ + struct sigaction oldact; + struct sigaction act; + // re-install the signal + if (!sigaction(theSignal, nullptr, &oldact)) { + if (sigaction(theSignal, &oldact, &act)) { + perror("sigaction"); + } + } + else { + perror("sigaction"); + } + + sigset_t set; + sigemptyset(&set); + switch (theSignal) { + case SIGHUP: + OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump(); + exit(SIGHUP); + break; + case SIGINT: + // For safe handling of Control-C as stop event, arm a variable but do not + // generate longjump (we are out of context anyway) + OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump(); + exit(SIGINT); + break; + case SIGQUIT: + OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump(); + exit(SIGQUIT); + break; + case SIGILL: + OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump(); + exit(SIGILL); + break; + case SIGKILL: + OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump(); + exit(SIGKILL); + break; + case SIGBUS: + sigaddset(&set, SIGBUS); + sigprocmask(SIG_UNBLOCK, &set, nullptr); + OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump(); + exit(SIGBUS); + break; + case SIGSEGV: + OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump(); + exit(SIGSEGV); + break; +# ifdef SIGSYS + case SIGSYS: + OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump(); + exit(SIGSYS); + break; +# endif + case SIGFPE: + sigaddset(&set, SIGFPE); + sigprocmask(SIG_UNBLOCK, &set, nullptr); + OSD::SetFloatingSignal(Standard_True); + Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump(); + break; + default: + break; + } +} + +static void setSignal(OSD_SignalMode theSignalMode) +{ + OSD_WasSetSignal = theSignalMode; + if (theSignalMode == OSD_SignalMode_AsIs) { + return; // nothing to be done with signal handlers + } + + // Prepare signal descriptors + struct sigaction anActSet; + struct sigaction anActDfl; + struct sigaction anActOld; + sigemptyset(&anActSet.sa_mask); + sigemptyset(&anActDfl.sa_mask); + sigemptyset(&anActOld.sa_mask); +# ifdef SA_RESTART + anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART; +# else + anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0; +# endif +# ifdef SA_SIGINFO + anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO; + anActSet.sa_sigaction = throw_exc; +# else + anActSet.sa_handler = throw_exc; +# endif + anActDfl.sa_handler = SIG_DFL; + + // Set signal handlers; NB: SIGSEGV must be the last one! + const int NBSIG = 8; + constexpr static std::array aSignalTypes + = {SIGFPE, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSYS, SIGSEGV}; + for (int aSignalType : aSignalTypes) { + // SIGSEGV has special handler + if (aSignalType == SIGSEGV) { +# ifdef SA_SIGINFO + anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler; +# else + anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler; +# endif + } + + // set handler according to specified mode and current handler + int retcode = -1; + if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) { + retcode = sigaction(aSignalType, &anActSet, &anActOld); + } + else if (theSignalMode == OSD_SignalMode_Unset) { + retcode = sigaction(aSignalType, &anActDfl, &anActOld); + } + if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0 + && anActOld.sa_handler != SIG_DFL) { + struct sigaction anActOld2; + sigemptyset(&anActOld2.sa_mask); + retcode = sigaction(aSignalType, &anActOld, &anActOld2); + } + Standard_ASSERT( + retcode == 0, + "sigaction() failed", + std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalType << std::endl + ); + } +} +#endif + +// ---------------------------------------------------------------------------- + +#if defined(__GNUC__) && defined(FC_OS_LINUX) +static OSD_SignalMode currentSignalMode = OSD_SignalMode_Unset; // NOLINT +#endif + +SignalException::SignalException() +{ +#if defined(__GNUC__) && defined(FC_OS_LINUX) + if (currentSignalMode == OSD_SignalMode_Unset) { + currentSignalMode = OSD_SignalMode_Set; + setSignal(currentSignalMode); + enabled = true; + } +#endif +} + +SignalException::~SignalException() +{ +#if defined(__GNUC__) && defined(FC_OS_LINUX) + if (enabled && currentSignalMode == OSD_SignalMode_Set) { + currentSignalMode = OSD_SignalMode_Unset; + setSignal(currentSignalMode); + // this is the default handler + Base::SystemHandler::installSegfaultHandler(); + } +#endif +} +// NOLINTEND(concurrency-mt-unsafe, cppcoreguidelines-pro-type-member-init) diff --git a/src/Mod/Part/App/SignalException.h b/src/Mod/Part/App/SignalException.h new file mode 100644 index 0000000000..fbd4f63d30 --- /dev/null +++ b/src/Mod/Part/App/SignalException.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2025 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#pragma once + +#include + +namespace Part +{ + +class PartExport SignalException +{ +public: + SignalException(); + ~SignalException(); + + SignalException(const SignalException&) = default; + SignalException(SignalException&&) = default; + SignalException& operator=(const SignalException&) = default; + SignalException& operator=(SignalException&&) = default; + +private: + bool enabled {false}; +}; + +} // namespace Part