Although it isn't supposed to happen there could be FDEs that cover the
same address range. Don't leak such FDEs and use an existing FDE for
consistency.

Signed-off-by: Mark Wielaard <m...@redhat.com>
---
 libdw/ChangeLog |  4 ++++
 libdw/fde.c     | 11 ++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 10df13b..f8b4793 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2015-12-02  Mark Wielaard  <m...@redhat.com>
+
+       * fde.c (intern_fde): Don't leak duplicate FDEs.
+
 2015-12-01  Mark Wielaard  <m...@redhat.com>
 
        * fde.c (intern_fde): Don't intern an fde that doesn't cover a
diff --git a/libdw/fde.c b/libdw/fde.c
index 2a59d3e..f5f6fbe 100644
--- a/libdw/fde.c
+++ b/libdw/fde.c
@@ -119,12 +119,21 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
     fde->instructions += cie->fde_augmentation_data_size;
 
   /* Add the new entry to the search tree.  */
-  if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL)
+  struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde);
+  if (tres == NULL)
     {
       free (fde);
       __libdw_seterrno (DWARF_E_NOMEM);
       return NULL;
     }
+  else if (*tres != fde)
+    {
+      /* There is already an FDE in the cache that covers the same
+        address range.  That is odd.  Ignore this FDE.  And just use
+        the one in the cache for consistency.  */
+      free (fde);
+      return *tres;
+    }
 
   return fde;
 }
-- 
2.5.0

Reply via email to