Blender  V2.93
creator_signals.c
Go to the documentation of this file.
1 /*
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.
6  *
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.
11  *
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.
15  */
16 
21 #ifndef WITH_PYTHON_MODULE
22 
23 # if defined(__linux__) && defined(__GNUC__)
24 # define _GNU_SOURCE
25 # include <fenv.h>
26 # endif
27 
28 # if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
29 # define OSX_SSE_FPE
30 # include <xmmintrin.h>
31 # endif
32 
33 # ifdef WIN32
34 # include <float.h>
35 # include <windows.h>
36 # endif
37 
38 # include <errno.h>
39 # include <stdlib.h>
40 # include <string.h>
41 
42 # include "BLI_sys_types.h"
43 
44 # ifdef WIN32
45 # include "BLI_winstuff.h"
46 # endif
47 # include "BLI_fileops.h"
48 # include "BLI_path_util.h"
49 # include "BLI_string.h"
50 # include "BLI_system.h"
51 # include "BLI_utildefines.h"
52 # include BLI_SYSTEM_PID_H
53 
54 # include "BKE_appdir.h" /* BKE_tempdir_base */
55 # include "BKE_blender_version.h"
56 # include "BKE_global.h"
57 # include "BKE_main.h"
58 # include "BKE_report.h"
59 
60 # include <signal.h>
61 
62 # ifdef WITH_PYTHON
63 # include "BPY_extern_python.h" /* BPY_python_backtrace */
64 # endif
65 
66 # include "creator_intern.h" /* own include */
67 
68 // #define USE_WRITE_CRASH_BLEND
69 # ifdef USE_WRITE_CRASH_BLEND
70 # include "BKE_undo_system.h"
71 # include "BLO_undofile.h"
72 # endif
73 
74 /* set breakpoints here when running in debug mode, useful to catch floating point errors */
75 # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
76 static void sig_handle_fpe(int UNUSED(sig))
77 {
78  fprintf(stderr, "debug: SIGFPE trapped\n");
79 }
80 # endif
81 
82 /* handling ctrl-c event in console */
83 # if !defined(WITH_HEADLESS)
84 static void sig_handle_blender_esc(int sig)
85 {
86  static int count = 0;
87 
88  G.is_break = true; /* forces render loop to read queue, not sure if its needed */
89 
90  if (sig == 2) {
91  if (count) {
92  printf("\nBlender killed\n");
93  exit(2);
94  }
95  printf("\nSent an internal break event. Press ^C again to kill Blender\n");
96  count++;
97  }
98 }
99 # endif
100 
101 static void sig_handle_crash_backtrace(FILE *fp)
102 {
103  fputs("\n# backtrace\n", fp);
105 }
106 
107 static void sig_handle_crash(int signum)
108 {
109  /* Might be called after WM/Main exit, so needs to be careful about NULL-checking before
110  * de-referencing. */
111 
112  wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL;
113 
114 # ifdef USE_WRITE_CRASH_BLEND
115  if (wm && wm->undo_stack) {
116  struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
117  if (memfile) {
118  char fname[FILE_MAX];
119 
120  if (!(G_MAIN && G_MAIN->name[0])) {
121  BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "crash.blend");
122  }
123  else {
124  BLI_strncpy(fname, G_MAIN->name, sizeof(fname));
125  BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend");
126  }
127 
128  printf("Writing: %s\n", fname);
129  fflush(stdout);
130 
131  BLO_memfile_write_file(memfile, fname);
132  }
133  }
134 # endif
135 
136  FILE *fp;
137  char header[512];
138 
139  char fname[FILE_MAX];
140 
141  if (!(G_MAIN && G_MAIN->name[0])) {
142  BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
143  }
144  else {
145  BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name));
146  BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
147  }
148 
149  printf("Writing: %s\n", fname);
150  fflush(stdout);
151 
152 # ifndef BUILD_DATE
153  BLI_snprintf(
154  header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
155 # else
156  BLI_snprintf(header,
157  sizeof(header),
158  "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
162  build_hash);
163 # endif
164 
165  /* open the crash log */
166  errno = 0;
167  fp = BLI_fopen(fname, "wb");
168  if (fp == NULL) {
169  fprintf(stderr,
170  "Unable to save '%s': %s\n",
171  fname,
172  errno ? strerror(errno) : "Unknown error opening file");
173  }
174  else {
175  if (wm) {
176  BKE_report_write_file_fp(fp, &wm->reports, header);
177  }
178 
180 
181 # ifdef WITH_PYTHON
182  /* Generate python back-trace if Python is currently active. */
184 # endif
185 
186  fclose(fp);
187  }
188 
189  /* Delete content of temp dir! */
191 
192  /* really crash */
193  signal(signum, SIG_DFL);
194 # ifndef WIN32
195  kill(getpid(), signum);
196 # else
197  TerminateProcess(GetCurrentProcess(), signum);
198 # endif
199 }
200 
201 # ifdef WIN32
202 extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
203 {
204  /* If this is a stack overflow then we can't walk the stack, so just try to show
205  * where the error happened */
206  if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
207  HMODULE mod;
208  CHAR modulename[MAX_PATH];
209  LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
210  fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n");
211  fprintf(stderr, "Address : 0x%p\n", address);
212  if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
213  if (GetModuleFileName(mod, modulename, MAX_PATH)) {
214  fprintf(stderr, "Module : %s\n", modulename);
215  }
216  }
217  }
218  else {
219  BLI_windows_handle_exception(ExceptionInfo);
220  sig_handle_crash(SIGSEGV);
221  }
222 
223  return EXCEPTION_EXECUTE_HANDLER;
224 }
225 # endif
226 
227 static void sig_handle_abort(int UNUSED(signum))
228 {
229  /* Delete content of temp dir! */
231 }
232 
234 {
236 # ifdef WIN32
237  SetUnhandledExceptionFilter(windows_exception_handler);
238 # else
239  /* after parsing args */
240  signal(SIGSEGV, sig_handle_crash);
241 # endif
242  }
243 
244 # ifdef WIN32
245  /* Prevent any error mode dialogs from hanging the application. */
246  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX |
247  SEM_NOOPENFILEERRORBOX);
248 # endif
249 
251  signal(SIGABRT, sig_handle_abort);
252  }
253 }
254 
256 {
257  /* for all platforms, even windows has it! */
258  BLI_assert(G.background);
259 
260 # if !defined(WITH_HEADLESS)
261  signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */
262 # endif
263 }
264 
266 {
267 # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
268  /* zealous but makes float issues a heck of a lot easier to find!
269  * set breakpoints on sig_handle_fpe */
270  signal(SIGFPE, sig_handle_fpe);
271 
272 # if defined(__linux__) && defined(__GNUC__)
273  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
274 # endif /* defined(__linux__) && defined(__GNUC__) */
275 # if defined(OSX_SSE_FPE)
276  /* OSX uses SSE for floating point by default, so here
277  * use SSE instructions to throw floating point exceptions */
278  _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK &
279  ~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
280 # endif /* OSX_SSE_FPE */
281 # if defined(_WIN32) && defined(_MSC_VER)
282  /* enables all fp exceptions */
283  _controlfp_s(NULL, 0, _MCW_EM);
284  /* hide the ones we don't care about */
285  _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
286 # endif /* _WIN32 && _MSC_VER */
287 # endif
288 }
289 
290 #endif /* WITH_PYTHON_MODULE */
void BKE_tempdir_session_purge(void)
Definition: appdir.c:1190
const char * BKE_tempdir_base(void)
Definition: appdir.c:1182
#define G_MAIN
Definition: BKE_global.h:232
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
Definition: report.c:321
#define BLI_assert(a)
Definition: BLI_assert.h:58
File and directory operations.
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1868
#define FILE_MAX
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1571
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
void BLI_system_backtrace(FILE *fp)
Definition: system.c:79
#define UNUSED(x)
Compatibility-like things for windows.
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
Definition: undofile.c:223
void BPY_python_backtrace(FILE *fp)
typedef LPVOID
char build_hash[]
Definition: buildinfo.c:47
char build_commit_date[]
Definition: buildinfo.c:49
char build_commit_time[]
Definition: buildinfo.c:50
struct ApplicationState app_state
Definition: creator.c:117
#define BLEND_VERSION_ARG
#define BLEND_VERSION_FMT
void main_signal_setup_background(void)
static void sig_handle_abort(int UNUSED(signum))
void main_signal_setup_fpe(void)
static void sig_handle_crash(int signum)
static void sig_handle_blender_esc(int sig)
void main_signal_setup(void)
static void sig_handle_crash_backtrace(FILE *fp)
int count
struct ApplicationState::@1182 signal
struct ReportList reports
struct UndoStack * undo_stack
void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception)
Definition: system_win32.c:391
ccl_device_inline int mod(int x, int m)
Definition: util_math.h:405
#define G(x, y, z)