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