From 35f16d649079ff085c3c2cd88df8626cdc020241 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Tue, 10 Dec 2019 12:16:05 +0100 Subject: [PATCH] [debugger] skip suspend for unattached threads (mono/mono#18105) When the debugger tries to suspend all the VM threads, it can happen with cooperative-suspend that it tries to suspend a thread that has previously been attached, but then did a "light" detach (that only unsets the domain). With the domain set to `NULL`, looking up a JitInfo for a given `ip` will result into a crash, but it isn't even necessarily needed for the purpose of suspending a thread. More details: Consider the following: ``` (lldb) c error: Process is running. Use 'process interrupt' to pause execution. Process 12832 stopped * thread mono/mono#9, name = 'tid_a31f', queue = 'NSOperationQueue 0x8069b670 (QOS: UTILITY)', stop reason = breakpoint 1.1 frame mono/mono#0: 0x00222870 WatchWCSessionAppWatchOSExtension`debugger_interrupt_critical(info=0x81365400, user_data=0xb04dc718) at debugger-agent.c:2716:6 2713 MonoDomain *domain = (MonoDomain *) mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN]; 2714 if (!domain) { 2715 /* not attached */ -> 2716 ji = NULL; 2717 } else { 2718 ji = mono_jit_info_table_find_internal ( domain, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx), TRUE, TRUE); 2719 } Target 0: (WatchWCSessionAppWatchOSExtension) stopped. (lldb) bt * thread mono/mono#9, name = 'tid_a31f', queue = 'NSOperationQueue 0x8069b670 (QOS: UTILITY)', stop reason = breakpoint 1.1 * frame mono/mono#0: 0x00222870 WatchWCSessionAppWatchOSExtension`debugger_interrupt_critical(info=0x81365400, user_data=0xb04dc718) at debugger-agent.c:2716:6 frame mono/mono#1: 0x004e177b WatchWCSessionAppWatchOSExtension`mono_thread_info_safe_suspend_and_run(id=0xb0767000, interrupt_kernel=0, callback=(WatchWCSessionAppWatchOSExtension`debugger_interrupt_critical at debugger-agent.c:2708), user_data=0xb04dc718) at mono-threads.c:1358:19 frame mono/mono#2: 0x00222799 WatchWCSessionAppWatchOSExtension`notify_thread(key=0x03994508, value=0x81378c00, user_data=0x00000000) at debugger-agent.c:2747:2 frame mono/mono#3: 0x00355bd8 WatchWCSessionAppWatchOSExtension`mono_g_hash_table_foreach(hash=0x8007b4e0, func=(WatchWCSessionAppWatchOSExtension`notify_thread at debugger-agent.c:2733), user_data=0x00000000) at mono-hash.c:310:4 frame mono/mono#4: 0x0021e955 WatchWCSessionAppWatchOSExtension`suspend_vm at debugger-agent.c:2844:3 frame mono/mono#5: 0x00225ff0 WatchWCSessionAppWatchOSExtension`process_event(event=EVENT_KIND_THREAD_START, arg=0x039945d0, il_offset=0, ctx=0x00000000, events=0x805b28e0, suspend_policy=2) at debugger-agent.c:4012:3 frame mono/mono#6: 0x00227c7c WatchWCSessionAppWatchOSExtension`process_profiler_event(event=EVENT_KIND_THREAD_START, arg=0x039945d0) at debugger-agent.c:4072:2 frame mono/mono#7: 0x0021b174 WatchWCSessionAppWatchOSExtension`thread_startup(prof=0x00000000, tid=2957889536) at debugger-agent.c:4149:2 frame mono/mono#8: 0x0037912d WatchWCSessionAppWatchOSExtension`mono_profiler_raise_thread_started(tid=2957889536) at profiler-events.h:103:1 frame mono/mono#9: 0x003d53da WatchWCSessionAppWatchOSExtension`fire_attach_profiler_events(tid=0xb04dd000) at threads.c:1120:2 frame mono/mono#10: 0x003d4d83 WatchWCSessionAppWatchOSExtension`mono_thread_attach(domain=0x801750a0) at threads.c:1547:2 frame mono/mono#11: 0x003df1a1 WatchWCSessionAppWatchOSExtension`mono_threads_attach_coop_internal(domain=0x801750a0, cookie=0xb04dcc0c, stackdata=0xb04dcba8) at threads.c:6008:3 frame mono/mono#12: 0x003df287 WatchWCSessionAppWatchOSExtension`mono_threads_attach_coop(domain=0x00000000, dummy=0xb04dcc0c) at threads.c:6045:9 frame mono/mono#13: 0x005034b8 WatchWCSessionAppWatchOSExtension`::xamarin_switch_gchandle(self=0x80762c20, to_weak=false) at runtime.m:1805:2 frame mono/mono#14: 0x005065c1 WatchWCSessionAppWatchOSExtension`::xamarin_retain_trampoline(self=0x80762c20, sel="retain") at trampolines.m:693:2 frame mono/mono#15: 0x657ea520 libobjc.A.dylib`objc_retain + 64 frame mono/mono#16: 0x4b4d9caa WatchConnectivity`__66-[WCSession onqueue_handleDictionaryMessageRequest:withPairingID:]_block_invoke + 279 frame mono/mono#17: 0x453c7df7 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12 frame mono/mono#18: 0x453c7cf4 Foundation`-[NSBlockOperation main] + 88 frame mono/mono#19: 0x453cacee Foundation`__NSOPERATION_IS_INVOKING_MAIN__ + 27 frame mono/mono#20: 0x453c6ebd Foundation`-[NSOperation start] + 835 frame mono/mono#21: 0x453cb606 Foundation`__NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 27 frame mono/mono#22: 0x453cb12e Foundation`__NSOQSchedule_f + 194 frame mono/mono#23: 0x453cb26e Foundation`____addOperations_block_invoke_4 + 20 frame mono/mono#24: 0x65de007b libdispatch.dylib`_dispatch_call_block_and_release + 15 frame mono/mono#25: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14 frame mono/mono#26: 0x65de3788 libdispatch.dylib`_dispatch_continuation_pop + 421 frame mono/mono#27: 0x65de2ee3 libdispatch.dylib`_dispatch_async_redirect_invoke + 818 frame mono/mono#28: 0x65df087d libdispatch.dylib`_dispatch_root_queue_drain + 354 frame mono/mono#29: 0x65df0ff3 libdispatch.dylib`_dispatch_worker_thread2 + 109 frame mono/mono#30: 0x66024fa0 libsystem_pthread.dylib`_pthread_wqthread + 208 frame mono/mono#31: 0x66024e44 libsystem_pthread.dylib`start_wqthread + 36 ``` Going further, `info` is about this thread: ``` (lldb) p/x *(int *)(((char *) info->node.key) + 0xa0) (int) $2 = 0x01243f93 (lldb) thread list Process 12832 stopped thread mono/mono#1: tid = 0x1243ee1, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'tid_303', queue = 'com.apple.main-thread' thread mono/mono#2: tid = 0x1243ee6, 0x65f816e2 libsystem_kernel.dylib`__recvfrom + 10 thread mono/mono#3: tid = 0x1243ee7, 0x65f81aea libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'SGen worker' thread mono/mono#4: tid = 0x1243ee9, 0x65f7e3d2 libsystem_kernel.dylib`semaphore_wait_trap + 10, name = 'Finalizer' thread mono/mono#5: tid = 0x1243eea, 0x65f816e2 libsystem_kernel.dylib`__recvfrom + 10, name = 'Debugger agent' thread mono/mono#6: tid = 0x1243f1d, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread' thread mono/mono#8: tid = 0x1243f93, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)' * thread mono/mono#9: tid = 0x12443a9, 0x00222870 WatchWCSessionAppWatchOSExtension`debugger_interrupt_critical(info=0x81365400, user_data=0xb04dc718) at debugger-agent.c:2716:6, name = 'tid_a31f', queue = 'NSOperationQueue 0x8069b670 (QOS: UTILITY)', stop reason = breakpoint 1.1 thread mono/mono#10: tid = 0x1244581, 0x65f7fd32 libsystem_kernel.dylib`__workq_kernreturn + 10 (lldb) thread select 8 * thread mono/mono#8, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)' frame mono/mono#0: 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10 libsystem_kernel.dylib`mach_msg_trap: -> 0x65f7e396 <+10>: retl 0x65f7e397 <+11>: nop libsystem_kernel.dylib`mach_msg_overwrite_trap: 0x65f7e398 <+0>: movl $0xffffffe0, %eax ; imm = 0xFFFFFFE0 0x65f7e39d <+5>: calll 0x65f85f44 ; _sysenter_trap (lldb) bt * thread mono/mono#8, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)' * frame mono/mono#0: 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10 frame mono/mono#1: 0x65f7e8ff libsystem_kernel.dylib`mach_msg + 47 frame mono/mono#2: 0x66079679 libxpc.dylib`_xpc_send_serializer + 104 frame mono/mono#3: 0x660794da libxpc.dylib`_xpc_pipe_simpleroutine + 80 frame mono/mono#4: 0x66079852 libxpc.dylib`xpc_pipe_simpleroutine + 43 frame mono/mono#5: 0x66043a8f libsystem_trace.dylib`___os_activity_stream_reflect_block_invoke_2 + 30 frame mono/mono#6: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14 frame mono/mono#7: 0x65de3d71 libdispatch.dylib`_dispatch_block_invoke_direct + 257 frame mono/mono#8: 0x65de3c62 libdispatch.dylib`dispatch_block_perform + 112 frame mono/mono#9: 0x6604349a libsystem_trace.dylib`_os_activity_stream_reflect + 725 frame mono/mono#10: 0x6604ef19 libsystem_trace.dylib`_os_log_impl_stream + 468 frame mono/mono#11: 0x6604e44d libsystem_trace.dylib`_os_log_impl_flatten_and_send + 6410 frame mono/mono#12: 0x6604cb3b libsystem_trace.dylib`_os_log + 137 frame mono/mono#13: 0x6604f4aa libsystem_trace.dylib`_os_log_impl + 31 frame mono/mono#14: 0x4b4eb4e9 WatchConnectivity`WCSerializePayloadDictionary + 393 frame mono/mono#15: 0x4b4d7c4d WatchConnectivity`-[WCSession onqueue_sendResponseDictionary:identifier:] + 195 frame mono/mono#16: 0x4b4da435 WatchConnectivity`__66-[WCSession onqueue_handleDictionaryMessageRequest:withPairingID:]_block_invoke.411 + 35 frame mono/mono#17: 0x453c7df7 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12 frame mono/mono#18: 0x453c7cf4 Foundation`-[NSBlockOperation main] + 88 frame mono/mono#19: 0x453cacee Foundation`__NSOPERATION_IS_INVOKING_MAIN__ + 27 frame mono/mono#20: 0x453c6ebd Foundation`-[NSOperation start] + 835 frame mono/mono#21: 0x453cb606 Foundation`__NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 27 frame mono/mono#22: 0x453cb12e Foundation`__NSOQSchedule_f + 194 frame mono/mono#23: 0x453cb067 Foundation`____addOperations_block_invoke_2 + 20 frame mono/mono#24: 0x65dedf49 libdispatch.dylib`_dispatch_block_async_invoke2 + 77 frame mono/mono#25: 0x65de4461 libdispatch.dylib`_dispatch_block_async_invoke_and_release + 17 frame mono/mono#26: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14 frame mono/mono#27: 0x65de3788 libdispatch.dylib`_dispatch_continuation_pop + 421 frame mono/mono#28: 0x65de2ee3 libdispatch.dylib`_dispatch_async_redirect_invoke + 818 frame mono/mono#29: 0x65df087d libdispatch.dylib`_dispatch_root_queue_drain + 354 frame mono/mono#30: 0x65df0ff3 libdispatch.dylib`_dispatch_worker_thread2 + 109 frame mono/mono#31: 0x66024fa0 libsystem_pthread.dylib`_pthread_wqthread + 208 frame mono/mono#32: 0x66024e44 libsystem_pthread.dylib`start_wqthread + 36 ``` which is a thread in a "light" detach state (aka. coop detach), where we only unset the domain: https://github.com/mono/mono/blob/mono/mono@4cefdcb7ce2d939ee78fb45d1b4913eb3bc064fd/mono/metadata/threads.c#L6084-L6111 Fixes https://github.com/mono/mono/issues/17926 Commit migrated from https://github.com/mono/mono/commit/80b1e103cbb30be9a206ccaa012d68a3d0bc0ca4 --- src/mono/mono/mini/debugger-agent.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 7d842cc..60163d6 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -2708,11 +2708,13 @@ debugger_interrupt_critical (MonoThreadInfo *info, gpointer user_data) MonoJitInfo *ji; data->valid_info = TRUE; - ji = mono_jit_info_table_find_internal ( - (MonoDomain *)mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN], - MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx), - TRUE, - TRUE); + MonoDomain *domain = (MonoDomain *) mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN]; + if (!domain) { + /* not attached */ + ji = NULL; + } else { + ji = mono_jit_info_table_find_internal ( domain, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx), TRUE, TRUE); + } /* This is signal safe */ thread_interrupt (data->tls, info, ji); -- 2.7.4