ASSERT utils.c:772 mutexval == LOCK_FREE_STATE || mutexval == LOCK_SET_STATE when signal arrives during thread exit
Just running the threadsig app with 30+ threads on my laptop hits this assert:
$ bin64/drrun -rstats_to_stderr -- ~/dr/test/threadsig 30 2000
<Starting application /home/bruening/dr/test/threadsig (137505)>
<Initial options = -no_dynamic_options -rstats_to_stderr -code_api -stack_size 56K -signal_stack_size 32K -max_elide_jmp 0 -max_elide_call 0 -early_inject -emulate_brk -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct >
<Paste into GDB to debug DynamoRIO clients:
set confirm off
add-symbol-file '/home/bruening/dr/git/build_x64_dbg_tests/lib64/debug/libdynamorio.so' 0x00007fa5fe191000
>
<(1+x) Handling our fault in a TRY at 0x00007fa5fe3efa38>
<get_memory_info mismatch! (can happen if os combines entries in /proc/pid/maps)
os says: 0x00007fa3b5740000-0x00007fa3b5f42000 prot=0x00000000
cache says: 0x00007fa3b5741000-0x00007fa3b5f41000 prot=0x00000003
>
<Application /home/bruening/dr/test/threadsig (137505). Internal Error: DynamoRIO debug check failure: /home/bruening/dr/git/src/core/utils.c:772 mutexval == LOCK_FREE_STATE || mutexval == LOCK_SET_STATE
(Error occurred @2978 frags)
version 8.0.18508, custom build
-no_dynamic_options -rstats_to_stderr -code_api -stack_size 56K -signal_stack_size 32K -max_elide_jmp 0 -max_elide_call 0 -early_inject -emulate_brk -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct >
#0 report_dynamorio_problem (dcontext=0x0, dumpcore_flag=8, exception_addr=0x0, report_ebp=0x0,
fmt=0x7ffff7ed34f0 "DynamoRIO debug check failure: %s:%d %s\n(Error occurred @%d frags)") at /home/bruening/dr/git/src/core/utils.c:2141
#1 0x00007ffff7c738dd in d_r_internal_error (file=0x7ffff7ed3390 "/home/bruening/dr/git/src/core/utils.c", line=772,
expr=0x7ffff7ed41b0 "mutexval == LOCK_FREE_STATE || mutexval == LOCK_SET_STATE") at /home/bruening/dr/git/src/core/utils.c:176
#2 0x00007ffff7c76076 in spinmutex_trylock (spin_lock=0x7ffdb3bceca0) at /home/bruening/dr/git/src/core/utils.c:772
#3 0x00007ffff7d69aac in thread_synch_check_state (dcontext=0x7ffdb3b86e00, desired_perm=THREAD_SYNCH_NO_LOCKS) at /home/bruening/dr/git/src/core/synch.c:208
#4 0x00007ffff7e75ec8 in record_pending_signal (dcontext=0x7ffdb3b86e00, sig=26, ucxt=0x7ffdb3ca7700, frame=0x7ffdb3ca76f8, forged=false, access_address=0x0)
at /home/bruening/dr/git/src/core/unix/signal.c:4290
#5 0x00007ffff7e79e21 in master_signal_handler_C (sig=26, siginfo=0x7ffdb3ca7830, ucxt=0x7ffdb3ca7700, xsp=0x7ffdb3ca76f8 "Y\205\343\367\377\177")
at /home/bruening/dr/git/src/core/unix/signal.c:5317
(gdb) p/x mutexval
$2 = 0xb3b63e78
(gdb) p/x * (thread_synch_data_t*) dcontext->synch_field
$11 = {
synch_lock = 0x7ffdb3bceca0,
pending_synch_count = 0xcdcdcdcd,
synch_perm = 0xcdcdcdcd,
synch_with_success = 0xcd,
set_mcontext = 0xcdcdcdcdcdcdcdcd,
set_context = 0xcdcdcdcdcdcdcdcd,
set_context_size = 0xcdcdcdcdcdcdcdcd,
set_context_alloc = 0xcdcdcdcdcdcdcdcd
}
So the synch_field is freed, which is why mutexval is bogus. The signal arrived during os_thread exit(), which is called after synch_thread_exit():
#0 d_r_mutex_lock_app (lock=0x7ffff7c76cad <d_r_write_lock+108>, mc=0x7ffdb3ca7df0) at /home/bruening/dr/git/src/core/utils.c:877
#1 0x00007ffff7e8c76e in memcache_lock () at /home/bruening/dr/git/src/core/unix/memcache.c:142
#2 0x00007ffff7e63479 in all_memory_areas_lock () at /home/bruening/dr/git/src/core/unix/os.c:7699
#3 0x00007ffff7d2fa9e in dynamo_vm_areas_lock () at /home/bruening/dr/git/src/core/vmareas.c:3579
#4 0x00007ffff7d0b450 in release_memory_and_update_areas (p=0x7ffdb3b5b000 '\253' <repeats 200 times>..., size=24576, decommit=false, remove_vm=true,
which=(VMM_SPECIAL_HEAP | VMM_PER_THREAD)) at /home/bruening/dr/git/src/core/heap.c:2736
#5 0x00007ffff7d0c053 in release_guarded_real_memory (p=0x7ffdb3b5b000 '\253' <repeats 200 times>..., size=24576, remove_vm=true, guarded=true,
which=(VMM_SPECIAL_HEAP | VMM_PER_THREAD)) at /home/bruening/dr/git/src/core/heap.c:2914
#6 0x00007ffff7d18029 in special_heap_exit (special=0x7ffdb3b8cb58) at /home/bruening/dr/git/src/core/heap.c:5352
#7 0x00007ffff7e6cfe6 in signal_thread_exit (dcontext=0x7ffdb3b86e00, other_thread=false) at /home/bruening/dr/git/src/core/unix/signal.c:1377
#8 0x00007ffff7e54a8c in os_thread_exit (dcontext=0x7ffdb3b86e00, other_thread=false) at /home/bruening/dr/git/src/core/unix/os.c:2438
#9 0x00007ffff7bee0e7 in dynamo_thread_exit_common (dcontext=0x7ffdb3b86e00, id=137888, other_thread=false) at /home/bruening/dr/git/src/core/dynamo.c:2629
#10 0x00007ffff7bee2b1 in dynamo_thread_exit () at /home/bruening/dr/git/src/core/dynamo.c:2709
#11 0x00007ffff7e384a3 in cat_thread_only () at /home/bruening/dr/git/src/core/arch/x86/x86.asm:625
dcontext->is_exiting is true and could possibly be used here: just drop the signal?