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. 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
