locs_tree is modified by three calls to eu_tsearch_nolock, each of which
occurs when intern_lock mutex is held.  All calls to eu_tfind* on
locs_tree occur when intern_lock is held except one, resulting in a data
race.

Fix this by changing this eu_tfind to eu_tfind_nolock and acquiring
intern_lock before it is called.

Signed-off-by: Aaron Merey <[email protected]>
---
 libdw/dwarf_getlocation.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index 6d7296f8..89f09874 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -166,17 +166,22 @@ dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, 
const Dwarf_Op *op,
   if (attr == NULL)
     return -1;
 
+  mutex_lock (attr->cu->intern_lock);
+
   struct loc_block_s fake = { .addr = (void *) op };
-  struct loc_block_s **found = eu_tfind (&fake, &attr->cu->locs_tree,
-                                        loc_compare);
+  struct loc_block_s **found = eu_tfind_nolock (&fake, &attr->cu->locs_tree,
+                                               loc_compare);
   if (unlikely (found == NULL))
     {
+      mutex_unlock (attr->cu->intern_lock);
       __libdw_seterrno (DWARF_E_NO_BLOCK);
       return -1;
     }
 
   return_block->length = (*found)->length;
   return_block->data = (*found)->data;
+
+  mutex_unlock (attr->cu->intern_lock);
   return 0;
 }
 
-- 
2.55.0

Reply via email to