diff --git a/CMakeLists.txt b/CMakeLists.txt index 48c5be450f..d0a72edc53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,8 @@ MESSAGE(STATUS "cmake: ${CMAKE_VERSION}") # ============================================================================== # == Win32 is default behaviour use the LibPack copied in Source tree ========== if(MSVC) - OPTION(FREECAD_RELEASE_PDB "Create PDB file for Release version." ON) + OPTION(FREECAD_RELEASE_PDB "Create PDB files for Release version." ON) + OPTION(FREECAD_RELEASE_SEH "Enable Structured Exception Handling for Release version." ON) OPTION(FREECAD_LIBPACK_USE "Use the LibPack to Build FreeCAD (only Win32 so far)." ON) OPTION(FREECAD_LIBPACK_USEPYSIDE "Use PySide in LibPack rather to PyQt and Swig." ON) set(FREECAD_LIBPACK_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Directory of the FreeCAD LibPack") @@ -1098,8 +1099,8 @@ ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) IF(MSVC) # set default compiler settings - SET (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /EHa /Zm128") - SET (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFC_DEBUG /Zm128") + SET (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zm150") + SET (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFC_DEBUG /Zm150") # set default libs SET (CMAKE_C_STANDARD_LIBRARIES "kernel32.lib user32.lib gdi32.lib winspool.lib SHFolder.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib winmm.lib comsupp.lib Ws2_32.lib dbghelp.lib ") set (CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}") @@ -1111,6 +1112,9 @@ IF(MSVC) set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") set (CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG") ENDIF(FREECAD_RELEASE_PDB) + IF(FREECAD_RELEASE_SEH) + SET (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /EHa") + ENDIF(FREECAD_RELEASE_SEH) # Mark 32 bit executables large address aware so they can use > 2GB address space # NOTE: This setting only has an effect on machines with at least 3GB of RAM, although it sets the linker option it doesn't set the linker switch 'Enable Large Addresses' diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 78d9c16acc..25c1d5b8a5 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -138,6 +138,10 @@ using namespace boost::program_options; #include #ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +# if !defined(_DEBUG) && defined(HAVE_SEH) +# define FC_SE_TRANSLATOR +# endif + # include # include // VC exception handling #else // Ansi C/C++ new handler @@ -1226,7 +1230,7 @@ void segmentation_fault_handler(int sig) } } -void my_terminate_handler() +void unhandled_exception_handler() { std::cerr << "Terminating..." << std::endl; } @@ -1242,23 +1246,28 @@ void unexpection_error_handler() #endif } -#ifdef _MSC_VER // Microsoft compiler - -void my_trans_func( unsigned int code, EXCEPTION_POINTERS* pExp ) +#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(); + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + throw Base::DivisionByZeroError("Division by zero!"); + break; + } - //switch (code) - //{ - // case FLT_DIVIDE_BY_ZERO : - // //throw CMyFunkyDivideByZeroException(code, pExp); - // throw Base::DivisionByZeroError("Division by zero!"); - // break; - //} - - // general C++ SEH exception for things we don't need to handle separately.... - throw Base::RuntimeError("my_trans_func()"); + 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 { @@ -1274,13 +1283,14 @@ void Application::init(int argc, char ** argv) #if defined (_MSC_VER) // Microsoft compiler std::signal(SIGSEGV,segmentation_fault_handler); std::signal(SIGABRT,segmentation_fault_handler); - std::set_terminate(my_terminate_handler); + std::set_terminate(unhandled_exception_handler); std::set_unexpected(unexpection_error_handler); -// _set_se_translator(my_trans_func); #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 initTypes(); #if (BOOST_VERSION < 104600) || (BOOST_FILESYSTEM_VERSION == 2) diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 6b826c81c8..5c5decfe13 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -3,6 +3,10 @@ if(WIN32) add_definitions(-DBOOST_DYN_LINK) endif(WIN32) +if(FREECAD_RELEASE_SEH) + add_definitions(-DHAVE_SEH) +endif(FREECAD_RELEASE_SEH) + # This causes some problems with the resource files to be found, especially with the StartPage IF(RESOURCEDIR) add_definitions(-DRESOURCEDIR="${RESOURCEDIR}") diff --git a/src/App/FeatureTest.cpp b/src/App/FeatureTest.cpp index b8e385365b..a6aa8479f9 100644 --- a/src/App/FeatureTest.cpp +++ b/src/App/FeatureTest.cpp @@ -131,29 +131,59 @@ short FeatureTest::mustExecute(void) const DocumentObjectExecReturn *FeatureTest::execute(void) { + /* +doc=App.newDocument() +obj=doc.addObject("App::FeatureTest") - int *i=0,j; - float f; - void *s; +obj.ExceptionType=0 # good +doc.recompute() - // Code analyzers may complain about some errors. This can be ignored - // because this is done on purpose to test the error handling mechanism - switch(ExceptionType.getValue()) - { - case 0: break; - case 1: throw "Test Exception"; - case 2: throw Base::RuntimeError("FeatureTestException::execute(): Testexception"); - case 3: *i=0;printf("%i",*i);break; // seg-vault - case 4: j=0; printf("%i",1/j); break; // int division by zero - case 5: f=0.0; printf("%f",1/f); break; // float division by zero - case 6: s = malloc(3600000000ul); free(s); break; // out-of-memory - } - - ExecCount.setValue(ExecCount.getValue() + 1); +obj.ExceptionType=1 # unknown exception +doc.recompute() - ExecResult.setValue("Exec"); +obj.ExceptionType=2 # Runtime error +doc.recompute() - return DocumentObject::StdReturn; +obj.ExceptionType=3 # segfault +doc.recompute() + +obj.ExceptionType=4 # segfault +doc.recompute() + +obj.ExceptionType=5 # int division by zero +doc.recompute() + +obj.ExceptionType=6 # float division by zero +doc.recompute() + */ + int *i=0,j; + float f; + void *s; + std::string t; + + // Code analyzers may complain about some errors. This can be ignored + // because this is done on purpose to test the error handling mechanism + switch(ExceptionType.getValue()) + { + case 0: break; + case 1: throw "Test Exception"; + case 2: throw Base::RuntimeError("FeatureTestException::execute(): Testexception"); +#if 0 // only allow these error types on purpose + case 3: *i=0;printf("%i",*i);break; // seg-fault + case 4: t = nullptr; break; // seg-fault + case 5: j=0; printf("%i",1/j); break; // int division by zero + case 6: f=0.0; printf("%f",1/f); break; // float division by zero + case 7: s = malloc(3600000000ul); free(s); break; // out-of-memory +#else + default: (void)i; (void)j; (void)f; (void)s; (void)t; break; +#endif + } + + ExecCount.setValue(ExecCount.getValue() + 1); + + ExecResult.setValue("Exec"); + + return DocumentObject::StdReturn; } @@ -162,14 +192,13 @@ PROPERTY_SOURCE(App::FeatureTestException, App::FeatureTest) FeatureTestException::FeatureTestException() { - ADD_PROPERTY(ExceptionType,(Base::Exception::getClassTypeId().getKey()) ); + ADD_PROPERTY(ExceptionType,(Base::Exception::getClassTypeId().getKey()) ); } DocumentObjectExecReturn *FeatureTestException::execute(void) { - //ExceptionType; + //ExceptionType; + throw Base::RuntimeError("FeatureTestException::execute(): Testexception ;-)"); - throw Base::RuntimeError("FeatureTestException::execute(): Testexception ;-)"); - - return 0; + return 0; } diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index eb67733d1c..e3edc18b67 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -237,7 +237,7 @@ PyMOD_INIT_FUNC(Part) // Python's cmath module. // For Linux use segmentation_fault_handler in Application.cpp #if !defined(_DEBUG) && !defined(FC_OS_LINUX) - OSD::SetSignal(Standard_False); + //OSD::SetSignal(Standard_False); #endif PyObject* partModule = Part::initModule();