Skip to content

Commit

Permalink
[debugger] skip suspend for unattached threads
Browse files Browse the repository at this point in the history
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#9, name = 'tid_a31f', queue = 'NSOperationQueue 0x8069b670 (QOS: UTILITY)', stop reason = breakpoint 1.1
    frame #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#9, name = 'tid_a31f', queue = 'NSOperationQueue 0x8069b670 (QOS: UTILITY)', stop reason = breakpoint 1.1
  * frame #0: 0x00222870 WatchWCSessionAppWatchOSExtension`debugger_interrupt_critical(info=0x81365400, user_data=0xb04dc718) at debugger-agent.c:2716:6
    frame 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#2: 0x00222799 WatchWCSessionAppWatchOSExtension`notify_thread(key=0x03994508, value=0x81378c00, user_data=0x00000000) at debugger-agent.c:2747:2
    frame 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#4: 0x0021e955 WatchWCSessionAppWatchOSExtension`suspend_vm at debugger-agent.c:2844:3
    frame 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#6: 0x00227c7c WatchWCSessionAppWatchOSExtension`process_profiler_event(event=EVENT_KIND_THREAD_START, arg=0x039945d0) at debugger-agent.c:4072:2
    frame mono#7: 0x0021b174 WatchWCSessionAppWatchOSExtension`thread_startup(prof=0x00000000, tid=2957889536) at debugger-agent.c:4149:2
    frame mono#8: 0x0037912d WatchWCSessionAppWatchOSExtension`mono_profiler_raise_thread_started(tid=2957889536) at profiler-events.h:103:1
    frame mono#9: 0x003d53da WatchWCSessionAppWatchOSExtension`fire_attach_profiler_events(tid=0xb04dd000) at threads.c:1120:2
    frame mono#10: 0x003d4d83 WatchWCSessionAppWatchOSExtension`mono_thread_attach(domain=0x801750a0) at threads.c:1547:2
    frame mono#11: 0x003df1a1 WatchWCSessionAppWatchOSExtension`mono_threads_attach_coop_internal(domain=0x801750a0, cookie=0xb04dcc0c, stackdata=0xb04dcba8) at threads.c:6008:3
    frame mono#12: 0x003df287 WatchWCSessionAppWatchOSExtension`mono_threads_attach_coop(domain=0x00000000, dummy=0xb04dcc0c) at threads.c:6045:9
    frame mono#13: 0x005034b8 WatchWCSessionAppWatchOSExtension`::xamarin_switch_gchandle(self=0x80762c20, to_weak=false) at runtime.m:1805:2
    frame mono#14: 0x005065c1 WatchWCSessionAppWatchOSExtension`::xamarin_retain_trampoline(self=0x80762c20, sel="retain") at trampolines.m:693:2
    frame mono#15: 0x657ea520 libobjc.A.dylib`objc_retain + 64
    frame mono#16: 0x4b4d9caa WatchConnectivity`__66-[WCSession onqueue_handleDictionaryMessageRequest:withPairingID:]_block_invoke + 279
    frame mono#17: 0x453c7df7 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame mono#18: 0x453c7cf4 Foundation`-[NSBlockOperation main] + 88
    frame mono#19: 0x453cacee Foundation`__NSOPERATION_IS_INVOKING_MAIN__ + 27
    frame mono#20: 0x453c6ebd Foundation`-[NSOperation start] + 835
    frame mono#21: 0x453cb606 Foundation`__NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 27
    frame mono#22: 0x453cb12e Foundation`__NSOQSchedule_f + 194
    frame mono#23: 0x453cb26e Foundation`____addOperations_block_invoke_4 + 20
    frame mono#24: 0x65de007b libdispatch.dylib`_dispatch_call_block_and_release + 15
    frame mono#25: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14
    frame mono#26: 0x65de3788 libdispatch.dylib`_dispatch_continuation_pop + 421
    frame mono#27: 0x65de2ee3 libdispatch.dylib`_dispatch_async_redirect_invoke + 818
    frame mono#28: 0x65df087d libdispatch.dylib`_dispatch_root_queue_drain + 354
    frame mono#29: 0x65df0ff3 libdispatch.dylib`_dispatch_worker_thread2 + 109
    frame mono#30: 0x66024fa0 libsystem_pthread.dylib`_pthread_wqthread + 208
    frame 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#1: tid = 0x1243ee1, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'tid_303', queue = 'com.apple.main-thread'
  thread mono#2: tid = 0x1243ee6, 0x65f816e2 libsystem_kernel.dylib`__recvfrom + 10
  thread mono#3: tid = 0x1243ee7, 0x65f81aea libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'SGen worker'
  thread mono#4: tid = 0x1243ee9, 0x65f7e3d2 libsystem_kernel.dylib`semaphore_wait_trap + 10, name = 'Finalizer'
  thread mono#5: tid = 0x1243eea, 0x65f816e2 libsystem_kernel.dylib`__recvfrom + 10, name = 'Debugger agent'
  thread mono#6: tid = 0x1243f1d, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
  thread mono#8: tid = 0x1243f93, 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)'
* thread 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#10: tid = 0x1244581, 0x65f7fd32 libsystem_kernel.dylib`__workq_kernreturn + 10
(lldb) thread select 8
* thread mono#8, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)'
    frame #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#8, name = 'tid_6d0f', queue = 'NSOperationQueue 0x8069b300 (QOS: UTILITY)'
  * frame #0: 0x65f7e396 libsystem_kernel.dylib`mach_msg_trap + 10
    frame mono#1: 0x65f7e8ff libsystem_kernel.dylib`mach_msg + 47
    frame mono#2: 0x66079679 libxpc.dylib`_xpc_send_serializer + 104
    frame mono#3: 0x660794da libxpc.dylib`_xpc_pipe_simpleroutine + 80
    frame mono#4: 0x66079852 libxpc.dylib`xpc_pipe_simpleroutine + 43
    frame mono#5: 0x66043a8f libsystem_trace.dylib`___os_activity_stream_reflect_block_invoke_2 + 30
    frame mono#6: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14
    frame mono#7: 0x65de3d71 libdispatch.dylib`_dispatch_block_invoke_direct + 257
    frame mono#8: 0x65de3c62 libdispatch.dylib`dispatch_block_perform + 112
    frame mono#9: 0x6604349a libsystem_trace.dylib`_os_activity_stream_reflect + 725
    frame mono#10: 0x6604ef19 libsystem_trace.dylib`_os_log_impl_stream + 468
    frame mono#11: 0x6604e44d libsystem_trace.dylib`_os_log_impl_flatten_and_send + 6410
    frame mono#12: 0x6604cb3b libsystem_trace.dylib`_os_log + 137
    frame mono#13: 0x6604f4aa libsystem_trace.dylib`_os_log_impl + 31
    frame mono#14: 0x4b4eb4e9 WatchConnectivity`WCSerializePayloadDictionary + 393
    frame mono#15: 0x4b4d7c4d WatchConnectivity`-[WCSession onqueue_sendResponseDictionary:identifier:] + 195
    frame mono#16: 0x4b4da435 WatchConnectivity`__66-[WCSession onqueue_handleDictionaryMessageRequest:withPairingID:]_block_invoke.411 + 35
    frame mono#17: 0x453c7df7 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame mono#18: 0x453c7cf4 Foundation`-[NSBlockOperation main] + 88
    frame mono#19: 0x453cacee Foundation`__NSOPERATION_IS_INVOKING_MAIN__ + 27
    frame mono#20: 0x453c6ebd Foundation`-[NSOperation start] + 835
    frame mono#21: 0x453cb606 Foundation`__NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 27
    frame mono#22: 0x453cb12e Foundation`__NSOQSchedule_f + 194
    frame mono#23: 0x453cb067 Foundation`____addOperations_block_invoke_2 + 20
    frame mono#24: 0x65dedf49 libdispatch.dylib`_dispatch_block_async_invoke2 + 77
    frame mono#25: 0x65de4461 libdispatch.dylib`_dispatch_block_async_invoke_and_release + 17
    frame mono#26: 0x65de126f libdispatch.dylib`_dispatch_client_callout + 14
    frame mono#27: 0x65de3788 libdispatch.dylib`_dispatch_continuation_pop + 421
    frame mono#28: 0x65de2ee3 libdispatch.dylib`_dispatch_async_redirect_invoke + 818
    frame mono#29: 0x65df087d libdispatch.dylib`_dispatch_root_queue_drain + 354
    frame mono#30: 0x65df0ff3 libdispatch.dylib`_dispatch_worker_thread2 + 109
    frame mono#31: 0x66024fa0 libsystem_pthread.dylib`_pthread_wqthread + 208
    frame 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/4cefdcb7ce2d939ee78fb45d1b4913eb3bc064fd/mono/metadata/threads.c#L6084-L6111

Fixes mono#17926
  • Loading branch information
lewurm authored and monojenkins committed Dec 11, 2019
1 parent da5b1c6 commit cf6037b
Showing 1 changed file with 7 additions and 5 deletions.
12 changes: 7 additions & 5 deletions mono/mini/debugger-agent.c
Expand Up @@ -2695,11 +2695,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);
Expand Down

0 comments on commit cf6037b

Please sign in to comment.