Hi Aaron, On Wed, Sep 30, 2026 at 03:06:48PM -0400, Aaron Merey wrote: > cache_op_table calls eu_tsearch_nolock on macro_ops_tree while holding > a macro_lock mutex. cache_op_table's fast path also contains a call to > eu_tfind on macro_ops_tree when macro_lock is not held. This creates a > data race where one thread may attempt to read macro_ops_tree with eu_tfind > while it's being modified by eu_tsearch_nolock in another thread. > > Fix this by using the locked variant of eu_tsearch instead, which shares > a lock with eu_tfind. > > There is an eu_tfind_nolock call in cache_op_table occurring while > macro_lock is held that remains a _nolock variant. Any modifications to > the tree or the node payloads occur when the macro_lock is held so > only reads of the tree and payloads occur concurrently.
This sound a bit complicated. The early "fast path" eu_tfind on macro_ops_tree isnt really "fast" since it does take the tree lock. Then if not found it still has to take the macro_lock. Then the tsearch also has to take the tree lock. So might it be easier/simpler to just get rid of the early "fast" path eu_find call and do everything (nolocked) under the macro_lock? Thanks, Mark > Signed-off-by: Aaron Merey <[email protected]> > --- > libdw/dwarf_getmacros.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c > index e3efd083..8ec7537d 100644 > --- a/libdw/dwarf_getmacros.c > +++ b/libdw/dwarf_getmacros.c > @@ -354,8 +354,8 @@ cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off > macoff, > return NULL; > } > > - Dwarf_Macro_Op_Table **ret = eu_tsearch_nolock (table, > &dbg->macro_ops_tree, > - macro_op_compare); > + Dwarf_Macro_Op_Table **ret = eu_tsearch (table, &dbg->macro_ops_tree, > + macro_op_compare); > mutex_unlock (dbg->macro_lock); > > if (unlikely (ret == NULL)) > -- > 2.55.0 >
