creator_signals.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. /** \file
  17. * \ingroup creator
  18. */
  19. #ifndef WITH_PYTHON_MODULE
  20. # if defined(__linux__) && defined(__GNUC__)
  21. # define _GNU_SOURCE
  22. # include <fenv.h>
  23. # endif
  24. # if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
  25. # define OSX_SSE_FPE
  26. # include <xmmintrin.h>
  27. # endif
  28. # ifdef WIN32
  29. # if defined(_MSC_VER) && defined(_M_X64)
  30. # include <math.h> /* needed for _set_FMA3_enable */
  31. # endif
  32. # include <windows.h>
  33. # include <float.h>
  34. # endif
  35. # include <stdlib.h>
  36. # include <string.h>
  37. # include <errno.h>
  38. # include "BLI_sys_types.h"
  39. # ifdef WIN32
  40. # include "BLI_winstuff.h"
  41. # endif
  42. # include "BLI_utildefines.h"
  43. # include "BLI_string.h"
  44. # include "BLI_path_util.h"
  45. # include "BLI_fileops.h"
  46. # include "BLI_system.h"
  47. # include BLI_SYSTEM_PID_H
  48. # include "BKE_appdir.h" /* BKE_tempdir_base */
  49. # include "BKE_blender_version.h"
  50. # include "BKE_global.h"
  51. # include "BKE_main.h"
  52. # include "BKE_report.h"
  53. # include <signal.h>
  54. # include "creator_intern.h" /* own include */
  55. // #define USE_WRITE_CRASH_BLEND
  56. # ifdef USE_WRITE_CRASH_BLEND
  57. # include "BKE_undo_system.h"
  58. # include "BLO_undofile.h"
  59. # endif
  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. /* handling ctrl-c event in console */
  68. # if !defined(WITH_HEADLESS)
  69. static void sig_handle_blender_esc(int sig)
  70. {
  71. static int count = 0;
  72. G.is_break = true; /* forces render loop to read queue, not sure if its needed */
  73. if (sig == 2) {
  74. if (count) {
  75. printf("\nBlender killed\n");
  76. exit(2);
  77. }
  78. printf("\nSent an internal break event. Press ^C again to kill Blender\n");
  79. count++;
  80. }
  81. }
  82. # endif
  83. static void sig_handle_crash_backtrace(FILE *fp)
  84. {
  85. fputs("\n# backtrace\n", fp);
  86. BLI_system_backtrace(fp);
  87. }
  88. static void sig_handle_crash(int signum)
  89. {
  90. wmWindowManager *wm = G_MAIN->wm.first;
  91. # ifdef USE_WRITE_CRASH_BLEND
  92. if (wm->undo_stack) {
  93. struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
  94. if (memfile) {
  95. char fname[FILE_MAX];
  96. if (!G_MAIN->name[0]) {
  97. BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
  98. }
  99. else {
  100. BLI_strncpy(fname, G_MAIN->name, sizeof(fname));
  101. BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend");
  102. }
  103. printf("Writing: %s\n", fname);
  104. fflush(stdout);
  105. BLO_memfile_write_file(memfile, fname);
  106. }
  107. }
  108. # endif
  109. FILE *fp;
  110. char header[512];
  111. char fname[FILE_MAX];
  112. if (!G_MAIN->name[0]) {
  113. BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
  114. }
  115. else {
  116. BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name));
  117. BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
  118. }
  119. printf("Writing: %s\n", fname);
  120. fflush(stdout);
  121. # ifndef BUILD_DATE
  122. BLI_snprintf(
  123. header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
  124. # else
  125. BLI_snprintf(header,
  126. sizeof(header),
  127. "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
  128. BLEND_VERSION_ARG,
  129. build_commit_date,
  130. build_commit_time,
  131. build_hash);
  132. # endif
  133. /* open the crash log */
  134. errno = 0;
  135. fp = BLI_fopen(fname, "wb");
  136. if (fp == NULL) {
  137. fprintf(stderr,
  138. "Unable to save '%s': %s\n",
  139. fname,
  140. errno ? strerror(errno) : "Unknown error opening file");
  141. }
  142. else {
  143. if (wm) {
  144. BKE_report_write_file_fp(fp, &wm->reports, header);
  145. }
  146. sig_handle_crash_backtrace(fp);
  147. fclose(fp);
  148. }
  149. /* Delete content of temp dir! */
  150. BKE_tempdir_session_purge();
  151. /* really crash */
  152. signal(signum, SIG_DFL);
  153. # ifndef WIN32
  154. kill(getpid(), signum);
  155. # else
  156. TerminateProcess(GetCurrentProcess(), signum);
  157. # endif
  158. }
  159. # ifdef WIN32
  160. LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
  161. {
  162. switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
  163. case EXCEPTION_ACCESS_VIOLATION:
  164. fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr);
  165. break;
  166. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  167. fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
  168. break;
  169. case EXCEPTION_BREAKPOINT:
  170. fputs("Error : EXCEPTION_BREAKPOINT\n", stderr);
  171. break;
  172. case EXCEPTION_DATATYPE_MISALIGNMENT:
  173. fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
  174. break;
  175. case EXCEPTION_FLT_DENORMAL_OPERAND:
  176. fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
  177. break;
  178. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  179. fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
  180. break;
  181. case EXCEPTION_FLT_INEXACT_RESULT:
  182. fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
  183. break;
  184. case EXCEPTION_FLT_INVALID_OPERATION:
  185. fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
  186. break;
  187. case EXCEPTION_FLT_OVERFLOW:
  188. fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr);
  189. break;
  190. case EXCEPTION_FLT_STACK_CHECK:
  191. fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr);
  192. break;
  193. case EXCEPTION_FLT_UNDERFLOW:
  194. fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr);
  195. break;
  196. case EXCEPTION_ILLEGAL_INSTRUCTION:
  197. fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
  198. break;
  199. case EXCEPTION_IN_PAGE_ERROR:
  200. fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr);
  201. break;
  202. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  203. fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
  204. break;
  205. case EXCEPTION_INT_OVERFLOW:
  206. fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr);
  207. break;
  208. case EXCEPTION_INVALID_DISPOSITION:
  209. fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr);
  210. break;
  211. case EXCEPTION_NONCONTINUABLE_EXCEPTION:
  212. fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
  213. break;
  214. case EXCEPTION_PRIV_INSTRUCTION:
  215. fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
  216. break;
  217. case EXCEPTION_SINGLE_STEP:
  218. fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr);
  219. break;
  220. case EXCEPTION_STACK_OVERFLOW:
  221. fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr);
  222. break;
  223. default:
  224. fputs("Error : Unrecognized Exception\n", stderr);
  225. break;
  226. }
  227. fflush(stderr);
  228. /* If this is a stack overflow then we can't walk the stack, so just show
  229. * where the error happened */
  230. if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
  231. HMODULE mod;
  232. CHAR modulename[MAX_PATH];
  233. LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
  234. fprintf(stderr, "Address : 0x%p\n", address);
  235. if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
  236. if (GetModuleFileName(mod, modulename, MAX_PATH)) {
  237. fprintf(stderr, "Module : %s\n", modulename);
  238. }
  239. }
  240. fflush(stderr);
  241. # ifdef NDEBUG
  242. TerminateProcess(GetCurrentProcess(), SIGSEGV);
  243. # else
  244. sig_handle_crash(SIGSEGV);
  245. # endif
  246. }
  247. return EXCEPTION_EXECUTE_HANDLER;
  248. }
  249. # endif
  250. static void sig_handle_abort(int UNUSED(signum))
  251. {
  252. /* Delete content of temp dir! */
  253. BKE_tempdir_session_purge();
  254. }
  255. void main_signal_setup(void)
  256. {
  257. if (app_state.signal.use_crash_handler) {
  258. # ifdef WIN32
  259. SetUnhandledExceptionFilter(windows_exception_handler);
  260. # else
  261. /* after parsing args */
  262. signal(SIGSEGV, sig_handle_crash);
  263. # endif
  264. }
  265. if (app_state.signal.use_abort_handler) {
  266. signal(SIGABRT, sig_handle_abort);
  267. }
  268. }
  269. void main_signal_setup_background(void)
  270. {
  271. /* for all platforms, even windos has it! */
  272. BLI_assert(G.background);
  273. # if !defined(WITH_HEADLESS)
  274. signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */
  275. # endif
  276. }
  277. void main_signal_setup_fpe(void)
  278. {
  279. # if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
  280. /* zealous but makes float issues a heck of a lot easier to find!
  281. * set breakpoints on sig_handle_fpe */
  282. signal(SIGFPE, sig_handle_fpe);
  283. # if defined(__linux__) && defined(__GNUC__)
  284. feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
  285. # endif /* defined(__linux__) && defined(__GNUC__) */
  286. # if defined(OSX_SSE_FPE)
  287. /* OSX uses SSE for floating point by default, so here
  288. * use SSE instructions to throw floating point exceptions */
  289. _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK &
  290. ~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
  291. # endif /* OSX_SSE_FPE */
  292. # if defined(_WIN32) && defined(_MSC_VER)
  293. /* enables all fp exceptions */
  294. _controlfp_s(NULL, 0, _MCW_EM);
  295. /* hide the ones we don't care about */
  296. _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
  297. # endif /* _WIN32 && _MSC_VER */
  298. # endif
  299. }
  300. #endif /* WITH_PYTHON_MODULE */