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