Skip to content

Commit 47c3747

Browse files
etrclaude
andcommitted
valgrind/helgrind: suppress libstdc++ _Sp_locker atomic<shared_ptr> FP
Run 29304424198 (3d6cf0b) drove helgrind from 168 residual errors down to a single one, and confirmed drd fully green (the MHD poll-listen `...` + MHD_queue_response frames landed). The lone remaining helgrind report is a libstdc++ atomic-shared-ptr false positive, not a libhttpserver locking race: Possible data race during read of size 8 ... std::_Sp_locker::_Sp_locker std::atomic_load_explicit<resource_hook_table>(shared_ptr*) httpserver::ensure_table (http_resource.cpp:96) httpserver::http_resource::add_hook (http_resource.cpp:214) ensure_table() uses the correct lock-free idiom — atomic_load_explicit(acquire) plus atomic_compare_exchange_strong_explicit(acq_rel) — so every concurrent access to hook_table_ goes through the std::atomic_* free functions. libstdc++ implements those with an internal _Sp_locker spinlock whose happens-before Helgrind cannot model (same blind spot as the _Sp_counted_base::_M_release entry already suppressed). TSan, which models the atomics precisely, is green on this same test — corroborating it is a detector artifact. Matched on the third-party _Sp_locker frame (never the libhttpserver caller): a genuinely unsynchronised shared_ptr access would surface a non-_Sp_locker frame and stay unsuppressed, so DR-008 is preserved. Mirrored into the drd supp for symmetry/future-proofing (drd did not flag it this run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NpysYDDJac63yz2mZKKiDf
1 parent 3d6cf0b commit 47c3747

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

test/valgrind-drd.supp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@
8282
fun:*_Sp_counted_base*_M_release*
8383
}
8484

85+
# --- libstdc++ atomic<shared_ptr> free-function ops (_Sp_locker spinlock) -----
86+
# std::atomic_load/atomic_compare_exchange on a std::shared_ptr take a
87+
# libstdc++-internal _Sp_locker spinlock whose happens-before DRD does not model,
88+
# so it can report a benign conflict between two correctly-synchronised atomic
89+
# accesses to the SAME shared_ptr (http_resource::hook_table_, via ensure_table's
90+
# atomic_load/compare_exchange lock-free idiom). Helgrind reports the mirror of
91+
# this; kept here in sync. Matched on the third-party _Sp_locker frame, never the
92+
# libhttpserver caller, so DR-008 is unaffected.
93+
{
94+
libstdcxx-atomic-shared-ptr-sp-locker
95+
drd:ConflictingAccess
96+
...
97+
fun:*_Sp_locker*
98+
}
99+
85100
# --- benign lock-free reads of immutable-after-registration resource config -
86101
# Written once at registration (before start()), only READ from the MHD worker
87102
# during dispatch. NOT a libhttpserver locking race (DR-008).

test/valgrind-helgrind.supp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,26 @@
7979
fun:*_Sp_counted_base*_M_release*
8080
}
8181

82+
# --- libstdc++ atomic<shared_ptr> free-function ops (_Sp_locker spinlock) -----
83+
# std::atomic_load/atomic_compare_exchange on a std::shared_ptr take a
84+
# libstdc++-internal _Sp_locker spinlock (global pool) to make the pointer +
85+
# control-block update atomic. Helgrind does not model that spinlock's
86+
# happens-before, so it reports a benign race between two correctly-synchronised
87+
# atomic accesses to the SAME shared_ptr -- here http_resource::hook_table_,
88+
# driven by ensure_table()'s atomic_load(acquire)/compare_exchange(acq_rel)
89+
# lock-free idiom when a handler calls add_hook() concurrently on multiple MHD
90+
# workers. Same detector blind spot as _Sp_counted_base::_M_release above; TSan,
91+
# which models the atomics precisely, reports NO race on this test. Matched on
92+
# the libstdc++ _Sp_locker frame (third-party) -- a genuinely unsynchronised
93+
# shared_ptr access would surface its own (non-_Sp_locker) frame and stay
94+
# unsuppressed, so DR-008 (libhttpserver's own locking) is unaffected.
95+
{
96+
libstdcxx-atomic-shared-ptr-sp-locker
97+
Helgrind:Race
98+
...
99+
fun:*_Sp_locker*
100+
}
101+
82102
# --- benign lock-free reads of immutable-after-registration resource config -
83103
# The method-dispatch table and a resource's allowed-method set are written
84104
# once at registration (before start()) and only READ from the MHD worker

0 commit comments

Comments
 (0)