DF-5674 / run.3.log
# run.3.log — probe (unlocked-free counter) + control + fix validation # probe library: /tmp/proprop = /usr/src/sys/libprop with a pthread_mutex_trylock # probe compiled into _prop_dict_keysym_free (see proprop_dictionary.c): # it counts every keysym free that starts while _prop_dict_keysym_tree_mutex # is NOT held by the freeing thread. root@dfbsd:/tmp # cc -O2 -DWITH_PROBE -o race_probe race_probe.c /tmp/proprop/libprop_probe.so -lpthread -Wl,-rpath,/tmp/proprop root@dfbsd:/tmp # cc -O2 -o race_fix race_attr.c /tmp/propfix/libprop_fix.so -lpthread -Wl,-rpath,/tmp/propfix root@dfbsd:/tmp # for i in 1 2 3; do ./race_probe; echo "--- probe run$i exit=$?"; done SIGSEGV in _prop_rb_tree_remove_node addr=0x8 SIGSEGV in _prop_rb_tree_insert_node addr=0x8 DF5674_unlocked_frees=1145 --- probe run1 exit=139 --- probe run2 exit=139 SIGSEGV in prop_object_iterator_release addr=0x8 DF5674_unlocked_frees=88 --- probe run3 exit=139 SIGSEGV in _prop_rb_tree_remove_node addr=0x0 DF5674_unlocked_frees=350 # (run interleaving above: each run prints its crash line(s) then the counter.) # Note run2: the victim is _prop_rb_tree_insert_node — the MUTEX-PROTECTED # inserter from _prop_dict_keysym_alloc walking a tree torn by the UNLOCKED # remover. DF5674_unlocked_frees 88..1145 per short run = direct proof the # frees execute without the tree mutex. # ---- control: identical workload, removes disabled (all tree ops locked) ---- root@dfbsd:/tmp # ./race_attr noremove # x3 survived exit=0 survived exit=0 survived exit=0 # ---- fix validation: libprop built from /tmp/propfix (fix.diff applied) ---- root@dfbsd:/tmp # for i in 1..10: ./race_fix > fixrun.$i.log (see fixrun.*.log summary in this pack; 10/10 runs print "survived" / exit=0)