* libdw/dwarf_end.c (cu_free): Free str_off_base_lock.
        * libdw/libdwP.h (struct Dwarf_CU): Add str_off_base_lock member.
        (str_offsets_base_off): Add locking.
        * libdw/libdw_findcu.c (__libdw_intern_next_unit): Initialize
        str_off_base_lock.

Signed-off-by: Aaron Merey <ame...@redhat.com>

---
v3 changes:
This patch replaces v2 04/10.  04/10 added a lock to dwarf_offdie that
was unnecessary but happened to prevent the reporting of a race condition
in str_offsets_base_off.  This patch addresses the source of the race
condition.

 libdw/dwarf_end.c    |  1 +
 libdw/libdwP.h       | 20 ++++++++++++++++++--
 libdw/libdw_findcu.c |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 92389c07..d8830823 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -70,6 +70,7 @@ cu_free (void *arg)
       Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
       rwlock_fini (p->abbrev_lock);
       rwlock_fini (p->split_lock);
+      mutex_fini (p->str_off_base_lock);
 
       /* Free split dwarf one way (from skeleton to split).  */
       if (p->unit_type == DW_UT_skeleton
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index d121914d..27e968ae 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -461,6 +461,10 @@ struct Dwarf_CU
      Covers __libdw_find_split_unit.  */
   rwlock_define(, split_lock);
 
+  /* Synchronize access to the str_off_base of this Dwarf_CU.
+     Covers __libdw_str_offsets_base_off.  */
+  mutex_define(, str_off_base_lock);
+
   /* Memory boundaries of this CU.  */
   void *startp;
   void *endp;
@@ -1202,6 +1206,7 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
   Dwarf_Off off = 0;
   if (cu != NULL)
     {
+      mutex_lock (cu->str_off_base_lock);
       if (cu->str_off_base == (Dwarf_Off) -1)
        {
          Dwarf_Off dwp_offset;
@@ -1216,6 +1221,7 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
              if (dwarf_formudata (&attr, &base) == 0)
                {
                  cu->str_off_base = off + base;
+                 mutex_unlock (cu->str_off_base_lock);
                  return cu->str_off_base;
                }
            }
@@ -1223,6 +1229,7 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
          if (cu->version < 5)
            {
              cu->str_off_base = off;
+             mutex_unlock (cu->str_off_base_lock);
              return cu->str_off_base;
            }
 
@@ -1230,7 +1237,12 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
            dbg = cu->dbg;
        }
       else
-       return cu->str_off_base;
+       {
+         mutex_unlock (cu->str_off_base_lock);
+         return cu->str_off_base;
+       }
+
+      mutex_unlock (cu->str_off_base_lock);
     }
 
   /* No str_offsets_base attribute, we have to assume "zero".
@@ -1280,7 +1292,11 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
 
  no_header:
   if (cu != NULL)
-    cu->str_off_base = off;
+    {
+      mutex_lock (cu->str_off_base_lock);
+      cu->str_off_base = off;
+      mutex_unlock (cu->str_off_base_lock);
+    }
 
   return off;
 }
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index 613f61c8..1e96110b 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -179,6 +179,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
   eu_search_tree_init (&newp->locs_tree);
   rwlock_init (newp->abbrev_lock);
   rwlock_init (newp->split_lock);
+  mutex_init (newp->str_off_base_lock);
 
   /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
   if (debug_types)
-- 
2.48.1

Reply via email to