dwarf_begin_elf might free memory for a struct Dwarf after its rwlock and
mutex fields have been initialized without calling the corresponding
destroy functions to release the lock resources.

Fix this by moving lock inits to the end of the valid_p function, after
the struct Dwarf being intialized has passed all error checking.

Signed-off-by: Aaron Merey <[email protected]>
---
 libdw/dwarf_begin_elf.c | 80 +++++++++++++++++++++++++----------------
 1 file changed, 49 insertions(+), 31 deletions(-)

diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index f5cabde0..dd30f79b 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -358,12 +358,6 @@ valid_p (Dwarf *result)
          result->fake_loc_cu->offset_size = 4;
          result->fake_loc_cu->version = 4;
          result->fake_loc_cu->split = NULL;
-         eu_search_tree_init (&result->fake_loc_cu->locs_tree);
-         rwlock_init (result->fake_loc_cu->split_lock);
-         mutex_init (result->fake_loc_cu->abbrev_lock);
-         mutex_init (result->fake_loc_cu->src_lock);
-         mutex_init (result->fake_loc_cu->str_off_base_lock);
-         mutex_init (result->fake_loc_cu->intern_lock);
        }
     }
 
@@ -391,12 +385,6 @@ valid_p (Dwarf *result)
          result->fake_loclists_cu->offset_size = 4;
          result->fake_loclists_cu->version = 5;
          result->fake_loclists_cu->split = NULL;
-         eu_search_tree_init (&result->fake_loclists_cu->locs_tree);
-         rwlock_init (result->fake_loclists_cu->split_lock);
-         mutex_init (result->fake_loclists_cu->abbrev_lock);
-         mutex_init (result->fake_loclists_cu->src_lock);
-         mutex_init (result->fake_loclists_cu->str_off_base_lock);
-         mutex_init (result->fake_loclists_cu->intern_lock);
        }
     }
 
@@ -429,19 +417,62 @@ valid_p (Dwarf *result)
          result->fake_addr_cu->offset_size = 4;
          result->fake_addr_cu->version = 5;
          result->fake_addr_cu->split = NULL;
-         eu_search_tree_init (&result->fake_addr_cu->locs_tree);
-         rwlock_init (result->fake_addr_cu->split_lock);
-         mutex_init (result->fake_addr_cu->abbrev_lock);
-         mutex_init (result->fake_addr_cu->src_lock);
-         mutex_init (result->fake_addr_cu->str_off_base_lock);
-         mutex_init (result->fake_addr_cu->intern_lock);
        }
     }
 
   if (result != NULL)
     {
+      if (pthread_rwlock_init(&result->mem_rwl, NULL) != 0)
+       {
+         free (result->fake_loc_cu);
+         free (result->fake_loclists_cu);
+         free (result->fake_addr_cu);
+         free (result);
+         __libdw_seterrno (DWARF_E_NOMEM); /* no memory.  */
+         return NULL;
+       }
+
       result->elfpath = __libdw_elfpath (result->elf->fildes);
       __libdw_set_debugdir(result);
+
+      /* Initialize locks and search_trees.  */
+      mutex_init (result->dwarf_lock);
+      mutex_init (result->macro_lock);
+      eu_search_tree_init (&result->cu_tree);
+      eu_search_tree_init (&result->tu_tree);
+      eu_search_tree_init (&result->split_tree);
+      eu_search_tree_init (&result->macro_ops_tree);
+      eu_search_tree_init (&result->files_lines_tree);
+
+      if (result->fake_loc_cu != NULL)
+       {
+         eu_search_tree_init (&result->fake_loc_cu->locs_tree);
+         rwlock_init (result->fake_loc_cu->split_lock);
+         mutex_init (result->fake_loc_cu->abbrev_lock);
+         mutex_init (result->fake_loc_cu->src_lock);
+         mutex_init (result->fake_loc_cu->str_off_base_lock);
+         mutex_init (result->fake_loc_cu->intern_lock);
+       }
+
+      if (result->fake_loclists_cu != NULL)
+       {
+         eu_search_tree_init (&result->fake_loclists_cu->locs_tree);
+         rwlock_init (result->fake_loclists_cu->split_lock);
+         mutex_init (result->fake_loclists_cu->abbrev_lock);
+         mutex_init (result->fake_loclists_cu->src_lock);
+         mutex_init (result->fake_loclists_cu->str_off_base_lock);
+         mutex_init (result->fake_loclists_cu->intern_lock);
+       }
+
+      if (result->fake_addr_cu != NULL)
+       {
+         eu_search_tree_init (&result->fake_addr_cu->locs_tree);
+         rwlock_init (result->fake_addr_cu->split_lock);
+         mutex_init (result->fake_addr_cu->abbrev_lock);
+         mutex_init (result->fake_addr_cu->src_lock);
+         mutex_init (result->fake_addr_cu->str_off_base_lock);
+         mutex_init (result->fake_addr_cu->intern_lock);
+       }
     }
 
   return result;
@@ -588,19 +619,6 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
      actual allocation.  */
   result->mem_default_size = mem_default_size;
   result->oom_handler = __libdw_oom;
-  if (pthread_rwlock_init(&result->mem_rwl, NULL) != 0)
-    {
-      free (result);
-      __libdw_seterrno (DWARF_E_NOMEM); /* no memory.  */
-      return NULL;
-    }
-  mutex_init (result->dwarf_lock);
-  mutex_init (result->macro_lock);
-  eu_search_tree_init (&result->cu_tree);
-  eu_search_tree_init (&result->tu_tree);
-  eu_search_tree_init (&result->split_tree);
-  eu_search_tree_init (&result->macro_ops_tree);
-  eu_search_tree_init (&result->files_lines_tree);
 
   result->mem_stacks = 0;
   result->mem_tails = NULL;
-- 
2.53.0

Reply via email to