@@ -914,6 +914,37 @@ assert_printer_callback (void)
914914 mono_dump_native_crash_info ("SIGABRT" , NULL , NULL );
915915}
916916
917+ #if !defined (HOST_WIN32 )
918+ /**
919+ * fork_crash_safe:
920+ *
921+ * Version of \c fork that is safe to call from an async context such as a
922+ * signal handler even if the process crashed inside libc.
923+ *
924+ * Returns 0 to the child process, >0 to the parent process or <0 on error.
925+ */
926+ static pid_t
927+ fork_crash_safe (void )
928+ {
929+ pid_t pid ;
930+ /*
931+ * glibc fork acquires some locks, so if the crash happened inside malloc/free,
932+ * it will deadlock. Call the syscall directly instead.
933+ */
934+ #if defined(HOST_ANDROID )
935+ /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
936+ g_assert_not_reached ();
937+ #elif !defined(HOST_DARWIN ) && defined(SYS_fork )
938+ pid = (pid_t ) syscall (SYS_fork );
939+ #elif HAVE_FORK
940+ pid = (pid_t ) fork ();
941+ #else
942+ g_assert_not_reached ();
943+ #endif
944+ return pid ;
945+ }
946+ #endif
947+
917948static void
918949dump_native_stacktrace (const char * signal , MonoContext * mctx )
919950{
@@ -956,159 +987,150 @@ dump_native_stacktrace (const char *signal, MonoContext *mctx)
956987 }
957988
958989#if !defined(HOST_WIN32 ) && defined(HAVE_SYS_SYSCALL_H ) && (defined(SYS_fork ) || HAVE_FORK )
959- if (!mini_debug_options .no_gdb_backtrace ) {
960- /* From g_spawn_command_line_sync () in eglib */
961- pid_t pid ;
962- int status ;
963- pid_t crashed_pid = getpid ();
990+ pid_t crashed_pid = getpid ();
964991
965992#ifndef DISABLE_CRASH_REPORTING
966- gchar * output = NULL ;
967- MonoStackHash hashes ;
968- MonoStateMem merp_mem ;
969- memset (& merp_mem , 0 , sizeof (merp_mem ));
970-
971- if (!double_faulted ) {
972- gboolean leave = FALSE;
973- gboolean dump_for_merp = FALSE;
993+ gchar * output = NULL ;
994+ MonoStackHash hashes ;
995+ MonoStateMem merp_mem ;
996+ memset (& merp_mem , 0 , sizeof (merp_mem ));
997+
998+ if (!double_faulted ) {
999+ gboolean leave = FALSE;
1000+ gboolean dump_for_merp = FALSE;
9741001#if defined(TARGET_OSX )
975- dump_for_merp = mono_merp_enabled ();
1002+ dump_for_merp = mono_merp_enabled ();
9761003#endif
9771004
9781005#ifndef DISABLE_STRUCTURED_CRASH
979- mini_register_sigterm_handler ();
1006+ mini_register_sigterm_handler ();
9801007#endif
9811008
982- if (!dump_for_merp ) {
1009+ if (!dump_for_merp ) {
9831010#ifdef DISABLE_STRUCTURED_CRASH
984- leave = TRUE;
1011+ leave = TRUE;
9851012#endif
986- }
1013+ }
9871014
988- MonoContext * passed_ctx = NULL ;
989- if (!leave && mctx ) {
990- passed_ctx = mctx ;
991- }
1015+ MonoContext * passed_ctx = NULL ;
1016+ if (!leave && mctx ) {
1017+ passed_ctx = mctx ;
1018+ }
9921019
993- g_async_safe_printf ("\n=================================================================\n" );
994- g_async_safe_printf ("\tTelemetry Dumper:\n" );
995- g_async_safe_printf ("=================================================================\n" );
1020+ g_async_safe_printf ("\n=================================================================\n" );
1021+ g_async_safe_printf ("\tTelemetry Dumper:\n" );
1022+ g_async_safe_printf ("=================================================================\n" );
9961023
997- if (!leave ) {
998- mono_summarize_timeline_start ();
999- mono_summarize_toggle_assertions (TRUE);
1024+ if (!leave ) {
1025+ mono_summarize_timeline_start ();
1026+ mono_summarize_toggle_assertions (TRUE);
10001027
1001- int mono_max_summary_len = 500000 ;
1002- int mono_state_tmp_file_tag = 1 ;
1003- mono_state_alloc_mem (& merp_mem , mono_state_tmp_file_tag , mono_max_summary_len * sizeof (gchar ));
1028+ int mono_max_summary_len = 500000 ;
1029+ int mono_state_tmp_file_tag = 1 ;
1030+ mono_state_alloc_mem (& merp_mem , mono_state_tmp_file_tag , mono_max_summary_len * sizeof (gchar ));
10041031
1005- // Returns success, so leave if !success
1006- leave = !mono_threads_summarize (passed_ctx , & output , & hashes , FALSE, TRUE, (gchar * ) merp_mem .mem , mono_max_summary_len );
1007- }
1032+ // Returns success, so leave if !success
1033+ leave = !mono_threads_summarize (passed_ctx , & output , & hashes , FALSE, TRUE, (gchar * ) merp_mem .mem , mono_max_summary_len );
1034+ }
10081035
1009- if (!leave ) {
1010- // Wait for the other threads to clean up and exit their handlers
1011- // We can't lock / wait indefinitely, in case one of these threads got stuck somehow
1012- // while dumping.
1013- g_async_safe_printf ("\nWaiting for dumping threads to resume\n" );
1014- sleep (1 );
1015- }
1036+ if (!leave ) {
1037+ // Wait for the other threads to clean up and exit their handlers
1038+ // We can't lock / wait indefinitely, in case one of these threads got stuck somehow
1039+ // while dumping.
1040+ g_async_safe_printf ("\nWaiting for dumping threads to resume\n" );
1041+ sleep (1 );
1042+ }
10161043
1017- // We want our crash, and don't have telemetry
1018- // So we dump to disk
1019- if (!leave && !dump_for_merp ) {
1020- mono_summarize_timeline_phase_log (MonoSummaryCleanup );
1021- mono_crash_dump (output , & hashes );
1022- mono_summarize_timeline_phase_log (MonoSummaryDone );
1023- mono_summarize_toggle_assertions (FALSE);
1024- }
1044+ // We want our crash, and don't have telemetry
1045+ // So we dump to disk
1046+ if (!leave && !dump_for_merp ) {
1047+ mono_summarize_timeline_phase_log (MonoSummaryCleanup );
1048+ mono_crash_dump (output , & hashes );
1049+ mono_summarize_timeline_phase_log (MonoSummaryDone );
1050+ mono_summarize_toggle_assertions (FALSE);
10251051 }
1052+ }
10261053#endif // DISABLE_CRASH_REPORTING
10271054
1028- /*
1029- * glibc fork acquires some locks, so if the crash happened inside malloc/free,
1030- * it will deadlock. Call the syscall directly instead.
1031- */
1032- #if defined(HOST_ANDROID )
1033- /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
1034- g_assert_not_reached ();
1035- #elif !defined(HOST_DARWIN ) && defined(SYS_fork )
1036- pid = (pid_t ) syscall (SYS_fork );
1037- #elif HAVE_FORK
1038- pid = (pid_t ) fork ();
1039- #else
1040- g_assert_not_reached ();
1055+ pid_t pid = crashed_pid ; /* init to some >0 value */
1056+ gboolean need_to_fork = !mini_debug_options .no_gdb_backtrace ;
1057+
1058+ #if defined (TARGET_OSX ) && !defined (DISABLE_CRASH_REPORTING )
1059+ need_to_fork |= mono_merp_enabled ();
10411060#endif
10421061
1062+ if (need_to_fork )
1063+ pid = fork_crash_safe ();
1064+
10431065#if defined (HAVE_PRCTL ) && defined(PR_SET_PTRACER )
1044- if (pid > 0 ) {
1045- // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
1046- // a value other than 0 (the most permissive ptrace scope). Most modern Linux
1047- // distributions set the scope to 1 which allows attaching only to direct children of
1048- // the current process
1049- prctl (PR_SET_PTRACER , pid , 0 , 0 , 0 );
1050- }
1066+ if (need_to_fork && pid > 0 ) {
1067+ // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
1068+ // a value other than 0 (the most permissive ptrace scope). Most modern Linux
1069+ // distributions set the scope to 1 which allows attaching only to direct children of
1070+ // the current process
1071+ prctl (PR_SET_PTRACER , pid , 0 , 0 , 0 );
1072+ }
10511073#endif
10521074
10531075#if defined(TARGET_OSX ) && !defined(DISABLE_CRASH_REPORTING )
1054- if (!double_faulted && mono_merp_enabled ()) {
1055- if (pid == 0 ) {
1056- if (output ) {
1057- gboolean merp_upload_success = mono_merp_invoke (crashed_pid , signal , output , & hashes );
1058-
1059- if (!merp_upload_success ) {
1060- g_async_safe_printf ("\nThe MERP upload step has failed.\n" );
1061- } else {
1062- // Remove
1063- g_async_safe_printf ("\nThe MERP upload step has succeeded.\n" );
1064- mono_summarize_timeline_phase_log (MonoSummaryDone );
1065- }
1066- mono_summarize_toggle_assertions (FALSE);
1076+ if (!double_faulted && mono_merp_enabled ()) {
1077+ /* FIXME: why are we running mono_merp_invoke in the forked process? */
1078+ if (pid == 0 ) {
1079+ if (output ) {
1080+ gboolean merp_upload_success = mono_merp_invoke (crashed_pid , signal , output , & hashes );
1081+
1082+ if (!merp_upload_success ) {
1083+ g_async_safe_printf ("\nThe MERP upload step has failed.\n" );
10671084 } else {
1068- g_async_safe_printf ("\nMerp dump step not run, no dump created.\n" );
1085+ // Remove
1086+ g_async_safe_printf ("\nThe MERP upload step has succeeded.\n" );
1087+ mono_summarize_timeline_phase_log (MonoSummaryDone );
10691088 }
1089+ mono_summarize_toggle_assertions (FALSE);
1090+ } else {
1091+ g_async_safe_printf ("\nMerp dump step not run, no dump created.\n" );
10701092 }
10711093 }
1094+ }
10721095#endif
10731096
1074- if (pid == 0 ) {
1075- dup2 (STDERR_FILENO , STDOUT_FILENO );
1076-
1077- g_async_safe_printf ("\n=================================================================\n" );
1078- g_async_safe_printf ("\tExternal Debugger Dump:\n" );
1079- g_async_safe_printf ("=================================================================\n" );
1080- mono_gdb_render_native_backtraces (crashed_pid );
1081- _exit (1 );
1082- } else if (pid > 0 ) {
1083- waitpid (pid , & status , 0 );
1084- } else {
1085- // If we can't fork, do as little as possible before exiting
1086- #ifndef DISABLE_CRASH_REPORTING
1087- output = NULL ;
1088- #endif
1089- }
1097+ if (!mini_debug_options .no_gdb_backtrace && pid == 0 ) {
1098+ dup2 (STDERR_FILENO , STDOUT_FILENO );
10901099
1091- if (double_faulted ) {
1092- g_async_safe_printf ("\nExiting early due to double fault.\n" );
1100+ g_async_safe_printf ("\n=================================================================\n" );
1101+ g_async_safe_printf ("\tExternal Debugger Dump:\n" );
1102+ g_async_safe_printf ("=================================================================\n" );
1103+ mono_gdb_render_native_backtraces (crashed_pid );
1104+ _exit (1 );
1105+ } else if (need_to_fork && pid > 0 ) {
1106+ int status ;
1107+ waitpid (pid , & status , 0 );
1108+ } else {
1109+ // If we can't fork, do as little as possible before exiting
10931110#ifndef DISABLE_CRASH_REPORTING
1094- mono_state_free_mem ( & merp_mem ) ;
1111+ output = NULL ;
10951112#endif
1096- _exit (-1 );
1097- }
1113+ }
10981114
1115+ if (double_faulted ) {
1116+ g_async_safe_printf ("\nExiting early due to double fault.\n" );
10991117#ifndef DISABLE_CRASH_REPORTING
1100- if (output ) {
1101- // We've already done our gdb dump and our telemetry steps. Before exiting,
1102- // see if we can notify any attached debugger instances.
1103- //
1104- // At this point we are accepting that the below step might end in a crash
1105- mini_get_dbg_callbacks ()-> send_crash (output , & hashes , 0 /* wait # seconds */ );
1106- }
1107- output = NULL ;
11081118 mono_state_free_mem (& merp_mem );
11091119#endif
1120+ _exit (-1 );
1121+ }
11101122
1123+ #ifndef DISABLE_CRASH_REPORTING
1124+ if (output ) {
1125+ // We've already done our gdb dump and our telemetry steps. Before exiting,
1126+ // see if we can notify any attached debugger instances.
1127+ //
1128+ // At this point we are accepting that the below step might end in a crash
1129+ mini_get_dbg_callbacks ()-> send_crash (output , & hashes , 0 /* wait # seconds */ );
11111130 }
1131+ output = NULL ;
1132+ mono_state_free_mem (& merp_mem );
1133+ #endif
11121134#endif
11131135#else
11141136#ifdef HOST_ANDROID
0 commit comments