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
> 

Reply via email to