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

Reply via email to