fake_{loc,loclists,addr}_cu are Dwarf_CUs that are created separate from
all the others, so their contents are minimal and mostly initialized by
a calloc. On dwarf_end however, they are freed through the same code path
as all the others, so they call DAH_free like all the others. This changes
that so that these three are exempt from DAH and split-DWARF matters, and
swaps the calloc for a malloc so Memcheck will catch any others.

Signed-off-by: Jonathon Anderson <jm...@rice.edu>
---
> O! Sorry. I now see your original approach was actually correct.  For
> some reason I believed the fake cus could have a split DWARF.  But of
> course they never have. The reason I gave was wrong, but I still like
> this patch a little better because it more explicitly sets the needed
> values.

How about a bit of both, I'll be happy if I don't initialize `unit_type`.
Does this work?

> Could you add a Signed-off-by and ChangeLog entry?

Sure thing.

 libdw/ChangeLog         |  6 ++++++
 libdw/dwarf_begin_elf.c | 18 +++++++++++++++---
 libdw/dwarf_end.c       | 23 ++++++++++++++---------
 3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 394c0df2..b1f73bc8 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2019-11-01  Jonathon Anderson  <jm...@rice.edu>
+
+       * dwarf_begin_elf.c (valid_p): Switch calloc for malloc for fake CUs.
+       Add explicit initialization of some fields.
+       * dwarf_end.c (cu_free): Add clause to limit freeing of CU internals.
+
 2019-08-26  Jonathon Anderson  <jm...@rice.edu>
 
        * libdw_alloc.c (__libdw_allocate): Added thread-safe stack allocator.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 8d137414..8c116847 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -223,7 +223,7 @@ valid_p (Dwarf *result)
      inside the .debug_loc or .debug_loclists section.  */
   if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
     {
-      result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+      result->fake_loc_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
       if (unlikely (result->fake_loc_cu == NULL))
        {
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -240,12 +240,16 @@ valid_p (Dwarf *result)
          result->fake_loc_cu->endp
            = (result->sectiondata[IDX_debug_loc]->d_buf
               + result->sectiondata[IDX_debug_loc]->d_size);
+         result->fake_loc_cu->locs = NULL;
+         result->fake_loc_cu->address_size = 0;
+         result->fake_loc_cu->version = 0;
+         result->fake_loc_cu->split = NULL;
        }
     }
 
   if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
     {
-      result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+      result->fake_loclists_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
       if (unlikely (result->fake_loclists_cu == NULL))
        {
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -263,6 +267,10 @@ valid_p (Dwarf *result)
          result->fake_loclists_cu->endp
            = (result->sectiondata[IDX_debug_loclists]->d_buf
               + result->sectiondata[IDX_debug_loclists]->d_size);
+         result->fake_loclists_cu->locs = NULL;
+         result->fake_loclists_cu->address_size = 0;
+         result->fake_loclists_cu->version = 0;
+         result->fake_loclists_cu->split = NULL;
        }
     }
 
@@ -272,7 +280,7 @@ valid_p (Dwarf *result)
      inside the .debug_addr section, if it exists.  */
   if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL)
     {
-      result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+      result->fake_addr_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
       if (unlikely (result->fake_addr_cu == NULL))
        {
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -291,6 +299,10 @@ valid_p (Dwarf *result)
          result->fake_addr_cu->endp
            = (result->sectiondata[IDX_debug_addr]->d_buf
               + result->sectiondata[IDX_debug_addr]->d_size);
+         result->fake_addr_cu->locs = NULL;
+         result->fake_addr_cu->address_size = 0;
+         result->fake_addr_cu->version = 0;
+         result->fake_addr_cu->split = NULL;
        }
     }
 
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index a2e94436..7e194a55 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -52,18 +52,23 @@ cu_free (void *arg)
 {
   struct Dwarf_CU *p = (struct Dwarf_CU *) arg;
 
-  Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
-
   tdestroy (p->locs, noop_free);
 
-  /* Free split dwarf one way (from skeleton to split).  */
-  if (p->unit_type == DW_UT_skeleton
-      && p->split != NULL && p->split != (void *)-1)
+  /* Only free the CU internals if its not a fake CU.  */
+  if(p != p->dbg->fake_loc_cu && p != p->dbg->fake_loclists_cu
+     && p != p->dbg->fake_addr_cu)
     {
-      /* The fake_addr_cu might be shared, only release one.  */
-      if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
-       p->split->dbg->fake_addr_cu = NULL;
-      INTUSE(dwarf_end) (p->split->dbg);
+      Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
+
+      /* Free split dwarf one way (from skeleton to split).  */
+      if (p->unit_type == DW_UT_skeleton
+         && p->split != NULL && p->split != (void *)-1)
+       {
+         /* The fake_addr_cu might be shared, only release one.  */
+         if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
+           p->split->dbg->fake_addr_cu = NULL;
+         INTUSE(dwarf_end) (p->split->dbg);
+       }
     }
 }
 
-- 
2.24.0.rc2

Reply via email to