]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Only intern CU when not EOF marker and cuoff points to a DIE.
authorMark Wielaard <mjw@redhat.com>
Thu, 7 May 2015 16:35:48 +0000 (18:35 +0200)
committerMark Wielaard <mjw@redhat.com>
Tue, 12 May 2015 14:54:05 +0000 (16:54 +0200)
We need to check the cuoff points to a real Dwarf_Die before trying to
intern the cu with tsearch. Otherwise bogus keys might end up in the
search tree with NULL cus. That will cause crashes in compare_cukey
during next insertion or deletion of cus. We also don't want to insert
the EOF marker and unconditionally tdestroy the lazy_cu_root. The EOF
could be caused by bad DWARF from a bogus agranges entry.

https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c30

Signed-off-by: Mark Wielaard <mjw@redhat.com>
libdwfl/ChangeLog
libdwfl/cu.c

index de76378d4839d5ab9986d1b614a84bd41487ea58..47f3854a88ae9201914c0397fffe543e22fa0e35 100644 (file)
@@ -1,3 +1,8 @@
+2015-05-07  Mark Wielaard  <mjw@redhat.com>
+
+       * cu.c (intern_cu): Check for EOF and check cuoff points to a real
+       Dwarf_Die before interning. Explicitly check EOF is expected.
+
 2015-05-05  Mark Wielaard  <mjw@redhat.com>
 
        * dwfl_lineinfo.c (dwfl_lineinfo): Check info->file is valid.
index 3ac341e4aa91c3275d59443557c99011497e0e01..5182054d3e16aca6404a7bf391e8f5835491d351 100644 (file)
@@ -171,63 +171,67 @@ compare_cukey (const void *a, const void *b)
 static Dwfl_Error
 intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
 {
-  struct Dwarf_CU dwkey;
-  struct dwfl_cu key;
-  key.die.cu = &dwkey;
-  dwkey.offset_size = 0;
-  dwkey.start = cuoff - (3 * 0 - 4 + 3);
-  struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
-  if (unlikely (found == NULL))
-    return DWFL_E_NOMEM;
-
-  if (*found == &key || *found == NULL)
+  if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
     {
-      if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
+      if (likely (mod->lazycu == 1))
        {
          /* This is the EOF marker.  Now we have interned all the CUs.
             One increment in MOD->lazycu counts not having hit EOF yet.  */
-         *found = *result = (void *) -1;
+         *result = (void *) -1;
          less_lazy (mod);
          return DWFL_E_NOERROR;
        }
       else
        {
-         /* This is a new entry, meaning we haven't looked at this CU.  */
+         /* Unexpected EOF, most likely a bogus aranges.  */
+         return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
+       }
+    }
 
-         *found = NULL;
+  /* Make sure the cuoff points to a real DIE.  */
+  Dwarf_Die cudie;
+  Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
+  if (die == NULL)
+    return DWFL_E_LIBDW;
 
-         struct dwfl_cu *cu = malloc (sizeof *cu);
-         if (unlikely (cu == NULL))
-           return DWFL_E_NOMEM;
+  struct Dwarf_CU dwkey;
+  struct dwfl_cu key;
+  key.die.cu = &dwkey;
+  dwkey.offset_size = 0;
+  dwkey.start = cuoff - (3 * 0 - 4 + 3);
+  struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
+  if (unlikely (found == NULL))
+    return DWFL_E_NOMEM;
 
-         cu->mod = mod;
-         cu->next = NULL;
-         cu->lines = NULL;
+  if (*found == &key || *found == NULL)
+    {
+      /* This is a new entry, meaning we haven't looked at this CU.  */
 
-         /* XXX use non-searching lookup */
-         Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
-         if (die == NULL)
-           {
-             free (cu);
-             return DWFL_E_LIBDW;
-           }
-         assert (die == &cu->die);
+      *found = NULL;
 
-         struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
-                                                      * sizeof (mod->cu[0])));
-         if (newvec == NULL)
-           {
-             free (cu);
-             return DWFL_E_NOMEM;
-           }
-         mod->cu = newvec;
+      struct dwfl_cu *cu = malloc (sizeof *cu);
+      if (unlikely (cu == NULL))
+       return DWFL_E_NOMEM;
 
-         mod->cu[mod->ncu++] = cu;
-         if (cu->die.cu->start == 0)
-           mod->first_cu = cu;
+      cu->mod = mod;
+      cu->next = NULL;
+      cu->lines = NULL;
+      cu->die = cudie;
 
-         *found = cu;
+      struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
+                                                  * sizeof (mod->cu[0])));
+      if (newvec == NULL)
+       {
+         free (cu);
+         return DWFL_E_NOMEM;
        }
+      mod->cu = newvec;
+
+      mod->cu[mod->ncu++] = cu;
+      if (cu->die.cu->start == 0)
+       mod->first_cu = cu;
+
+      *found = cu;
     }
 
   *result = *found;