Fix build error on Windows 32 bit.
[blender-staging.git] / source / creator / creator_signals.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file creator/creator_signals.c
22  *  \ingroup creator
23  */
24
25 #ifndef WITH_PYTHON_MODULE
26
27 #if defined(__linux__) && defined(__GNUC__)
28 #  define _GNU_SOURCE
29 #  include <fenv.h>
30 #endif
31
32 #if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
33 #  define OSX_SSE_FPE
34 #  include <xmmintrin.h>
35 #endif
36
37 #ifdef WIN32
38 #  if defined(_MSC_VER) && defined(_M_X64)
39 #    include <math.h> /* needed for _set_FMA3_enable */
40 #  endif
41 #  include <windows.h>
42 #  include <float.h>
43 #endif
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <errno.h>
48
49 #include "BLI_sys_types.h"
50
51 #ifdef WIN32
52 #  include "BLI_winstuff.h"
53 #endif
54 #include "BLI_utildefines.h"
55 #include "BLI_string.h"
56 #include "BLI_path_util.h"
57 #include "BLI_fileops.h"
58 #include "BLI_system.h"
59 #include BLI_SYSTEM_PID_H
60
61 #include "BKE_appdir.h"  /* BKE_tempdir_base */
62 #include "BKE_blender_version.h"
63 #include "BKE_global.h"
64 #include "BKE_main.h"
65 #include "BKE_report.h"
66
67 /* for passing information between creator and gameengine */
68 #ifdef WITH_GAMEENGINE
69 #  include "BL_System.h"
70 #else /* dummy */
71 #  define SYS_SystemHandle int
72 #endif
73
74 #include <signal.h>
75
76 #include "creator_intern.h"  /* own include */
77
78 /* set breakpoints here when running in debug mode, useful to catch floating point errors */
79 #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
80 static void sig_handle_fpe(int UNUSED(sig))
81 {
82         fprintf(stderr, "debug: SIGFPE trapped\n");
83 }
84 #endif
85
86 /* handling ctrl-c event in console */
87 #if !defined(WITH_HEADLESS)
88 static void sig_handle_blender_esc(int sig)
89 {
90         static int count = 0;
91
92         G.is_break = true;  /* forces render loop to read queue, not sure if its needed */
93
94         if (sig == 2) {
95                 if (count) {
96                         printf("\nBlender killed\n");
97                         exit(2);
98                 }
99                 printf("\nSent an internal break event. Press ^C again to kill Blender\n");
100                 count++;
101         }
102 }
103 #endif
104
105 static void sig_handle_crash_backtrace(FILE *fp)
106 {
107         fputs("\n# backtrace\n", fp);
108         BLI_system_backtrace(fp);
109 }
110
111 static void sig_handle_crash(int signum)
112 {
113
114 #if 0
115         {
116                 char fname[FILE_MAX];
117
118                 if (!G.main->name[0]) {
119                         BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
120                 }
121                 else {
122                         BLI_strncpy(fname, G.main->name, sizeof(fname));
123                         BLI_replace_extension(fname, sizeof(fname), ".crash.blend");
124                 }
125
126                 printf("Writing: %s\n", fname);
127                 fflush(stdout);
128
129                 BKE_undo_save_file(fname);
130         }
131 #endif
132
133         FILE *fp;
134         char header[512];
135         wmWindowManager *wm = G.main->wm.first;
136
137         char fname[FILE_MAX];
138
139         if (!G.main->name[0]) {
140                 BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
141         }
142         else {
143                 BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G.main->name));
144                 BLI_replace_extension(fname, sizeof(fname), ".crash.txt");
145         }
146
147         printf("Writing: %s\n", fname);
148         fflush(stdout);
149
150 #ifndef BUILD_DATE
151         BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
152 #else
153         BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
154                      BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash);
155 #endif
156
157         /* open the crash log */
158         errno = 0;
159         fp = BLI_fopen(fname, "wb");
160         if (fp == NULL) {
161                 fprintf(stderr, "Unable to save '%s': %s\n",
162                         fname, errno ? strerror(errno) : "Unknown error opening file");
163         }
164         else {
165                 if (wm) {
166                         BKE_report_write_file_fp(fp, &wm->reports, header);
167                 }
168
169                 sig_handle_crash_backtrace(fp);
170
171                 fclose(fp);
172         }
173
174         /* Delete content of temp dir! */
175         BKE_tempdir_session_purge();
176
177         /* really crash */
178         signal(signum, SIG_DFL);
179 #ifndef WIN32
180         kill(getpid(), signum);
181 #else
182         TerminateProcess(GetCurrentProcess(), signum);
183 #endif
184 }
185
186 #ifdef WIN32
187 LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
188 {
189         switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
190                 case EXCEPTION_ACCESS_VIOLATION:
191                         fputs("Error   : EXCEPTION_ACCESS_VIOLATION\n", stderr);
192                         break;
193                 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
194                         fputs("Error   : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
195                         break;
196                 case EXCEPTION_BREAKPOINT:
197                         fputs("Error   : EXCEPTION_BREAKPOINT\n", stderr);
198                         break;
199                 case EXCEPTION_DATATYPE_MISALIGNMENT:
200                         fputs("Error   : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
201                         break;
202                 case EXCEPTION_FLT_DENORMAL_OPERAND:
203                         fputs("Error   : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
204                         break;
205                 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
206                         fputs("Error   : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
207                         break;
208                 case EXCEPTION_FLT_INEXACT_RESULT:
209                         fputs("Error   : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
210                         break;
211                 case EXCEPTION_FLT_INVALID_OPERATION:
212                         fputs("Error   : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
213                         break;
214                 case EXCEPTION_FLT_OVERFLOW:
215                         fputs("Error   : EXCEPTION_FLT_OVERFLOW\n", stderr);
216                         break;
217                 case EXCEPTION_FLT_STACK_CHECK:
218                         fputs("Error   : EXCEPTION_FLT_STACK_CHECK\n", stderr);
219                         break;
220                 case EXCEPTION_FLT_UNDERFLOW:
221                         fputs("Error   : EXCEPTION_FLT_UNDERFLOW\n", stderr);
222                         break;
223                 case EXCEPTION_ILLEGAL_INSTRUCTION:
224                         fputs("Error   : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
225                         break;
226                 case EXCEPTION_IN_PAGE_ERROR:
227                         fputs("Error   : EXCEPTION_IN_PAGE_ERROR\n", stderr);
228                         break;
229                 case EXCEPTION_INT_DIVIDE_BY_ZERO:
230                         fputs("Error   : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
231                         break;
232                 case EXCEPTION_INT_OVERFLOW:
233                         fputs("Error   : EXCEPTION_INT_OVERFLOW\n", stderr);
234                         break;
235                 case EXCEPTION_INVALID_DISPOSITION:
236                         fputs("Error   : EXCEPTION_INVALID_DISPOSITION\n", stderr);
237                         break;
238                 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
239                         fputs("Error   : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
240                         break;
241                 case EXCEPTION_PRIV_INSTRUCTION:
242                         fputs("Error   : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
243                         break;
244                 case EXCEPTION_SINGLE_STEP:
245                         fputs("Error   : EXCEPTION_SINGLE_STEP\n", stderr);
246                         break;
247                 case EXCEPTION_STACK_OVERFLOW:
248                         fputs("Error   : EXCEPTION_STACK_OVERFLOW\n", stderr);
249                         break;
250                 default:
251                         fputs("Error   : Unrecognized Exception\n", stderr);
252                         break;
253         }
254
255         fflush(stderr);
256
257         /* If this is a stack overflow then we can't walk the stack, so just show
258          * where the error happened */
259         if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
260                 HMODULE mod;
261                 CHAR modulename[MAX_PATH];
262                 LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
263
264                 fprintf(stderr, "Address : 0x%p\n", address);
265                 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
266                         if (GetModuleFileName(mod, modulename, MAX_PATH)) {
267                                 fprintf(stderr, "Module  : %s\n", modulename);
268                         }
269                 }
270
271                 fflush(stderr);
272
273 #ifdef NDEBUG
274                 TerminateProcess(GetCurrentProcess(), SIGSEGV);
275 #else
276                 sig_handle_crash(SIGSEGV);
277 #endif
278         }
279
280         return EXCEPTION_EXECUTE_HANDLER;
281 }
282 #endif
283
284 static void sig_handle_abort(int UNUSED(signum))
285 {
286         /* Delete content of temp dir! */
287         BKE_tempdir_session_purge();
288 }
289
290
291 void main_signal_setup(void)
292 {
293         if (app_state.signal.use_crash_handler) {
294 #ifdef WIN32
295                 SetUnhandledExceptionFilter(windows_exception_handler);
296 #else
297                 /* after parsing args */
298                 signal(SIGSEGV, sig_handle_crash);
299 #endif
300         }
301
302         if (app_state.signal.use_abort_handler) {
303                 signal(SIGABRT, sig_handle_abort);
304         }
305 }
306
307 void main_signal_setup_background(void)
308 {
309         /* for all platforms, even windos has it! */
310         BLI_assert(G.background);
311
312 #if !defined(WITH_HEADLESS)
313         signal(SIGINT, sig_handle_blender_esc);  /* ctrl c out bg render */
314 #endif
315 }
316
317
318 void main_signal_setup_fpe(void)
319 {
320 #if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
321         /* zealous but makes float issues a heck of a lot easier to find!
322          * set breakpoints on sig_handle_fpe */
323         signal(SIGFPE, sig_handle_fpe);
324
325 # if defined(__linux__) && defined(__GNUC__)
326         feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
327 # endif /* defined(__linux__) && defined(__GNUC__) */
328 # if defined(OSX_SSE_FPE)
329         /* OSX uses SSE for floating point by default, so here
330          * use SSE instructions to throw floating point exceptions */
331         _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK & ~
332                                (_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
333 # endif /* OSX_SSE_FPE */
334 # if defined(_WIN32) && defined(_MSC_VER)
335         _controlfp_s(NULL, 0, _MCW_EM); /* enables all fp exceptions */
336         _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); /* hide the ones we don't care about */
337 # endif /* _WIN32 && _MSC_VER */
338 #endif
339 }
340
341 #endif  /* WITH_PYTHON_MODULE */