2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 /** \file \ingroup creator
20 #ifndef WITH_PYTHON_MODULE
22 #if defined(__linux__) && defined(__GNUC__)
27 #if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
29 # include <xmmintrin.h>
33 # if defined(_MSC_VER) && defined(_M_X64)
34 # include <math.h> /* needed for _set_FMA3_enable */
44 #include "BLI_sys_types.h"
47 # include "BLI_winstuff.h"
49 #include "BLI_utildefines.h"
50 #include "BLI_string.h"
51 #include "BLI_path_util.h"
52 #include "BLI_fileops.h"
53 #include "BLI_system.h"
54 #include BLI_SYSTEM_PID_H
56 #include "BKE_appdir.h" /* BKE_tempdir_base */
57 #include "BKE_blender_version.h"
58 #include "BKE_global.h"
60 #include "BKE_report.h"
64 #include "creator_intern.h" /* own include */
66 // #define USE_WRITE_CRASH_BLEND
67 #ifdef USE_WRITE_CRASH_BLEND
68 # include "BKE_undo_system.h"
69 # include "BLO_undofile.h"
72 /* set breakpoints here when running in debug mode, useful to catch floating point errors */
73 #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
74 static void sig_handle_fpe(int UNUSED(sig))
76 fprintf(stderr, "debug: SIGFPE trapped\n");
80 /* handling ctrl-c event in console */
81 #if !defined(WITH_HEADLESS)
82 static void sig_handle_blender_esc(int sig)
86 G.is_break = true; /* forces render loop to read queue, not sure if its needed */
90 printf("\nBlender killed\n");
93 printf("\nSent an internal break event. Press ^C again to kill Blender\n");
99 static void sig_handle_crash_backtrace(FILE *fp)
101 fputs("\n# backtrace\n", fp);
102 BLI_system_backtrace(fp);
105 static void sig_handle_crash(int signum)
107 wmWindowManager *wm = G_MAIN->wm.first;
109 #ifdef USE_WRITE_CRASH_BLEND
110 if (wm->undo_stack) {
111 struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
113 char fname[FILE_MAX];
115 if (!G_MAIN->name[0]) {
116 BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
119 BLI_strncpy(fname, G_MAIN->name, sizeof(fname));
120 BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend");
123 printf("Writing: %s\n", fname);
126 BLO_memfile_write_file(memfile, fname);
134 char fname[FILE_MAX];
136 if (!G_MAIN->name[0]) {
137 BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
140 BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name));
141 BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
144 printf("Writing: %s\n", fname);
148 BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
150 BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
151 BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash);
154 /* open the crash log */
156 fp = BLI_fopen(fname, "wb");
158 fprintf(stderr, "Unable to save '%s': %s\n",
159 fname, errno ? strerror(errno) : "Unknown error opening file");
163 BKE_report_write_file_fp(fp, &wm->reports, header);
166 sig_handle_crash_backtrace(fp);
171 /* Delete content of temp dir! */
172 BKE_tempdir_session_purge();
175 signal(signum, SIG_DFL);
177 kill(getpid(), signum);
179 TerminateProcess(GetCurrentProcess(), signum);
184 LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
186 switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
187 case EXCEPTION_ACCESS_VIOLATION:
188 fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr);
190 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
191 fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
193 case EXCEPTION_BREAKPOINT:
194 fputs("Error : EXCEPTION_BREAKPOINT\n", stderr);
196 case EXCEPTION_DATATYPE_MISALIGNMENT:
197 fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
199 case EXCEPTION_FLT_DENORMAL_OPERAND:
200 fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
202 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
203 fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
205 case EXCEPTION_FLT_INEXACT_RESULT:
206 fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
208 case EXCEPTION_FLT_INVALID_OPERATION:
209 fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
211 case EXCEPTION_FLT_OVERFLOW:
212 fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr);
214 case EXCEPTION_FLT_STACK_CHECK:
215 fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr);
217 case EXCEPTION_FLT_UNDERFLOW:
218 fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr);
220 case EXCEPTION_ILLEGAL_INSTRUCTION:
221 fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
223 case EXCEPTION_IN_PAGE_ERROR:
224 fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr);
226 case EXCEPTION_INT_DIVIDE_BY_ZERO:
227 fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
229 case EXCEPTION_INT_OVERFLOW:
230 fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr);
232 case EXCEPTION_INVALID_DISPOSITION:
233 fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr);
235 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
236 fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
238 case EXCEPTION_PRIV_INSTRUCTION:
239 fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
241 case EXCEPTION_SINGLE_STEP:
242 fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr);
244 case EXCEPTION_STACK_OVERFLOW:
245 fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr);
248 fputs("Error : Unrecognized Exception\n", stderr);
254 /* If this is a stack overflow then we can't walk the stack, so just show
255 * where the error happened */
256 if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
258 CHAR modulename[MAX_PATH];
259 LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
261 fprintf(stderr, "Address : 0x%p\n", address);
262 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
263 if (GetModuleFileName(mod, modulename, MAX_PATH)) {
264 fprintf(stderr, "Module : %s\n", modulename);
271 TerminateProcess(GetCurrentProcess(), SIGSEGV);
273 sig_handle_crash(SIGSEGV);
277 return EXCEPTION_EXECUTE_HANDLER;
281 static void sig_handle_abort(int UNUSED(signum))
283 /* Delete content of temp dir! */
284 BKE_tempdir_session_purge();
288 void main_signal_setup(void)
290 if (app_state.signal.use_crash_handler) {
292 SetUnhandledExceptionFilter(windows_exception_handler);
294 /* after parsing args */
295 signal(SIGSEGV, sig_handle_crash);
299 if (app_state.signal.use_abort_handler) {
300 signal(SIGABRT, sig_handle_abort);
304 void main_signal_setup_background(void)
306 /* for all platforms, even windos has it! */
307 BLI_assert(G.background);
309 #if !defined(WITH_HEADLESS)
310 signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */
315 void main_signal_setup_fpe(void)
317 #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
318 /* zealous but makes float issues a heck of a lot easier to find!
319 * set breakpoints on sig_handle_fpe */
320 signal(SIGFPE, sig_handle_fpe);
322 # if defined(__linux__) && defined(__GNUC__)
323 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
324 # endif /* defined(__linux__) && defined(__GNUC__) */
325 # if defined(OSX_SSE_FPE)
326 /* OSX uses SSE for floating point by default, so here
327 * use SSE instructions to throw floating point exceptions */
328 _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK & ~
329 (_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
330 # endif /* OSX_SSE_FPE */
331 # if defined(_WIN32) && defined(_MSC_VER)
332 /* enables all fp exceptions */
333 _controlfp_s(NULL, 0, _MCW_EM);
334 /* hide the ones we don't care about */
335 _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
336 # endif /* _WIN32 && _MSC_VER */
340 #endif /* WITH_PYTHON_MODULE */