Blender V5.0
creator_signals.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#ifndef WITH_PYTHON_MODULE
10
11# include <cerrno>
12# include <cstdlib>
13
14# if defined(__linux__) && defined(__GNUC__)
15# ifndef _GNU_SOURCE
16# define _GNU_SOURCE
17# endif
18# include <cfenv>
19# endif
20
21# if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
22# define OSX_SSE_FPE
23# include <xmmintrin.h>
24# endif
25
26# ifdef WIN32
27# include <float.h>
28# include <windows.h>
29
30# include "BLI_winstuff.h"
31
32# include "GPU_platform.hh"
33# endif
34
35# include "BLI_fileops.h"
36# include "BLI_path_utils.hh"
37# include "BLI_string.h"
38# include "BLI_system.h"
39# include BLI_SYSTEM_PID_H
40
41# include "BKE_appdir.hh" /* #BKE_tempdir_session_purge. */
42# include "BKE_blender.hh"
43# include "BKE_blender_version.h"
44# include "BKE_global.hh"
45# include "BKE_main.hh"
46# include "BKE_report.hh"
47# include "BKE_wm_runtime.hh"
48
49# include <csignal>
50
51# ifdef WITH_PYTHON
52# include "BPY_extern_python.hh" /* #BPY_python_backtrace. */
53# endif
54
55# include "creator_intern.h" /* Own include. */
56
57# if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
61static void sig_handle_fpe(int /*sig*/)
62{
63 fprintf(stderr, "debug: SIGFPE trapped\n");
64}
65# endif
66
67/* Handling `Ctrl-C` event in the console. */
68static void sig_handle_blender_esc(int sig)
69{
70 /* Forces render loop to read queue, not sure if its needed. */
71 G.is_break = true;
72
73 if (sig == 2) {
74 static int count = 0;
75 if (count) {
76 printf("\nBlender killed\n");
77 exit(2);
78 }
79 printf("\nSent an internal break event. Press ^C again to kill Blender\n");
80 count++;
81 }
82}
83
84static void crashlog_file_generate(const char *filepath, const void *os_info)
85{
86 /* Might be called after WM/Main exit, so needs to be careful about nullptr-checking before
87 * de-referencing. */
88
89 wmWindowManager *wm = G_MAIN ? static_cast<wmWindowManager *>(G_MAIN->wm.first) : nullptr;
90
91 FILE *fp;
92 char header[512];
93
94 printf("Writing: %s\n", filepath);
95 fflush(stdout);
96
97# ifndef BUILD_DATE
98 SNPRINTF(header, "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
99# else
100 SNPRINTF(header,
101 "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
105 build_hash);
106# endif
107
108 /* Open the crash log. */
109 errno = 0;
110 fp = BLI_fopen(filepath, "wb");
111 if (fp == nullptr) {
112 fprintf(stderr,
113 "Unable to save '%s': %s\n",
114 filepath,
115 errno ? strerror(errno) : "Unknown error opening file");
116 }
117 else {
118 if (wm) {
119 BKE_report_write_file_fp(fp, &wm->runtime->reports, header);
120 }
121
122 fputs("\n# backtrace\n", fp);
124
125# ifdef WITH_PYTHON
126 /* Generate python back-trace if Python is currently active. */
128# endif
129
130 fclose(fp);
131 }
132}
133
134static void sig_cleanup_and_terminate(int signum)
135{
136 /* Delete content of temp directory. */
138
139 /* Really crash. */
140 signal(signum, SIG_DFL);
141# ifndef WIN32
142 kill(getpid(), signum);
143# else
144 TerminateProcess(GetCurrentProcess(), signum);
145# endif
146}
147
148static void sig_handle_crash_fn(int signum)
149{
150 char filepath_crashlog[FILE_MAX];
151 BKE_blender_globals_crash_path_get(filepath_crashlog);
152 crashlog_file_generate(filepath_crashlog, nullptr);
154}
155
156# ifdef WIN32
157extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
158{
159 /* If this is a stack overflow then we can't walk the stack, so just try to show
160 * where the error happened. */
161 if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
162 HMODULE mod;
163 CHAR modulename[MAX_PATH];
164 LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
165 fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n");
166 fprintf(stderr, "Address : 0x%p\n", address);
167 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, LPCSTR(address), &mod)) {
168 if (GetModuleFileName(mod, modulename, MAX_PATH)) {
169 fprintf(stderr, "Module : %s\n", modulename);
170 }
171 }
172 }
173 else {
174 char filepath_crashlog[FILE_MAX];
176 BKE_blender_globals_crash_path_get(filepath_crashlog);
177 crashlog_file_generate(filepath_crashlog, ExceptionInfo);
178
179 /* Disable popup in background mode to avoid blocking automation.
180 * (e.g., when used by a render farm; see #142314). */
181 if (!G.background) {
182 std::string version;
183# ifndef BUILD_DATE
184 const char *build_hash = G_MAIN ? G_MAIN->build_hash : "unknown";
185 version = std::string(BKE_blender_version_string()) + ", hash: `" + build_hash + "`";
186# else
187 version = std::string(BKE_blender_version_string()) + ", Commit date: " + build_commit_date +
188 " " + build_commit_time + ", hash: `" + build_hash + "`";
189# endif
190
192 filepath_crashlog, G.filepath_last_blend, GPU_platform_gpu_name(), version.c_str());
193 }
195 }
196
197 return EXCEPTION_EXECUTE_HANDLER;
198}
199# endif
200
201static void sig_handle_abort(int /*signum*/)
202{
203 /* Delete content of temp directory. */
205}
206
208{
209 if (app_state.signal.use_crash_handler) {
210# ifdef WIN32
211 SetUnhandledExceptionFilter(windows_exception_handler);
212# else
213 /* After parsing arguments. */
214 signal(SIGSEGV, sig_handle_crash_fn);
215# endif
216 }
217
218# ifdef WIN32
219 /* Prevent any error mode dialogs from hanging the application. */
220 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX |
221 SEM_NOOPENFILEERRORBOX);
222# endif
223
224 if (app_state.signal.use_abort_handler) {
225 signal(SIGABRT, sig_handle_abort);
226 }
227}
228
230{
231 /* for all platforms, even windows has it! */
232 BLI_assert(G.background);
233
234 /* Support pressing `Ctrl-C` to close Blender in background-mode.
235 * Useful to be able to cancel a render operation. */
236 signal(SIGINT, sig_handle_blender_esc);
237}
238
240{
241# if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
242 /* Zealous but makes float issues a heck of a lot easier to find!
243 * Set breakpoints on #sig_handle_fpe. */
244 signal(SIGFPE, sig_handle_fpe);
245
246# if defined(__linux__) && defined(__GNUC__) && defined(HAVE_FEENABLEEXCEPT)
247 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
248# endif /* defined(__linux__) && defined(__GNUC__) */
249# if defined(OSX_SSE_FPE)
250 /* OSX uses SSE for floating point by default, so here
251 * use SSE instructions to throw floating point exceptions. */
252 _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK &
253 ~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
254# endif /* OSX_SSE_FPE */
255# if defined(_WIN32) && defined(_MSC_VER)
256 /* Enables all floating-point exceptions. */
257 _controlfp_s(nullptr, 0, _MCW_EM);
258 /* Hide the ones we don't care about. */
259 _controlfp_s(nullptr, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
260# endif /* _WIN32 && _MSC_VER */
261# endif
262}
263
264#endif /* WITH_PYTHON_MODULE */
void BKE_tempdir_session_purge()
Definition appdir.cc:1248
Blender util stuff.
void BKE_blender_globals_crash_path_get(char *filepath)
const char * BKE_blender_version_string(void)
Definition blender.cc:146
#define G_MAIN
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
Definition report.cc:397
#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()
#define FILE_MAX
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
void BLI_system_backtrace_with_os_info(FILE *fp, const void *os_info)
Definition system.cc:64
Compatibility-like things for windows.
void BPY_python_backtrace(FILE *fp)
const char * GPU_platform_gpu_name()
char build_hash[]
Definition bpy_app.cc:70
char build_commit_date[]
Definition bpy_app.cc:68
char build_commit_time[]
Definition bpy_app.cc:69
ApplicationState app_state
Definition creator.cc:126
#define BLEND_VERSION_ARG
#define BLEND_VERSION_FMT
static void crashlog_file_generate(const char *filepath, const void *os_info)
static void sig_handle_abort(int)
void main_signal_setup_background()
static void sig_cleanup_and_terminate(int signum)
void main_signal_setup_fpe()
static void sig_handle_crash_fn(int signum)
static void sig_handle_blender_esc(int sig)
void main_signal_setup()
#define printf(...)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
int count
#define G(x, y, z)
WindowManagerRuntimeHandle * runtime
void BLI_windows_exception_print_message(const void *os_info)
void BLI_windows_exception_show_dialog(const char *filepath_crashlog, const char *filepath_relaunch, const char *gpu_name, const char *build_version)