The scenario goes like this.
* end iterator has an offset of 1
* begin iterator has an offset of 0
* operator ++ does essentially the following:
  _m_offset = ::dwarf_getattrs (&_m_die._m_die, &getattrs_callback,
                                (void *) this, _m_offset);
* operator == takes into account "parental" DIE and _m_offset

getattrs_callback is done such that it answers CB_OK when called the first time (then it also initializes _m_attr.value), and CB_ABORT when called the second time. This way dwarf_getattrs returns the position of _next_ attribute in sequence. But that means that when the last argument is loaded in _m_attr, _m_offset already has a value of 1, and evaluates as equal to the end iterator.

As a fix for that, I propose to consider also NULL-ness of _m_attr.value when doing the iterator comparison. On empty sequences, the callback is never called, thus leaving _m_attr.value NULL. On sequence of one element, _m_offset will end up being 1, but _m_attr.value will be non-NULL. Only after the call to ++ will _m_attr.value become NULL, and dwarf_getattrs, seeing offset of 1, will immediately return 1 again without calling the callback. Etc.

Patch attached.

PM
From 3e9c7e605e666ef32d1dddd93f9d303ebd801e67 Mon Sep 17 00:00:00 2001
From: Petr Machata <[email protected]>
Date: Tue, 24 Mar 2009 15:04:53 +0100
Subject: [PATCH] <dwarf>: Don't swallow last attribute

---
 libdw/ChangeLog |    5 +++++
 libdw/c++/dwarf |   11 ++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index fc08176..d68075d 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2009-03-24  Petr Machata  <[email protected]>
+
+       * c++/dwarf (dwarf::debug_info_entry::raw_attributes):
+       Fix iteration over attributes.
+
 2009-02-26  Roland McGrath  <[email protected]>
 
        * c++/dwarf (dwarf::attr_value): Add _m_tag private member.
diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf
index 862b9a1..33e7250 100644
--- a/libdw/c++/dwarf
+++ b/libdw/c++/dwarf
@@ -626,7 +626,10 @@ namespace elfutils
        }
 
        inline const_iterator (const debug_info_entry &die, ptrdiff_t offset)
-         : _m_die (die), _m_offset (offset) {}
+         : _m_die (die), _m_offset (offset)
+       {
+         _m_attr.valp = NULL;
+       }
 
       public:
        inline const_iterator (const const_iterator &i)
@@ -643,7 +646,8 @@ namespace elfutils
        inline bool operator== (const const_iterator &other) const
        {
          return (_m_die._m_die.addr == other._m_die._m_die.addr
-                 && _m_offset == other._m_offset);
+                 && _m_offset == other._m_offset
+                 && !_m_attr.valp == !other._m_attr.valp);
        }
        inline bool operator!= (const const_iterator &other) const
        {
@@ -659,6 +663,7 @@ namespace elfutils
          _m_offset = result;
          return *this;
        }
+
        inline const_iterator operator++ (int) // postfix
        {
          const_iterator prev = *this;
@@ -668,7 +673,7 @@ namespace elfutils
 
        inline attribute operator* () const
        {
-         if (unlikely (_m_offset == 1))
+         if (unlikely (_m_offset == 1 && _m_attr.valp == NULL))
            throw std::runtime_error ("dereferencing end iterator");
          return attribute (_m_die, _m_attr);
        }
-- 
1.6.0.6

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
elfutils-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/elfutils-devel

Reply via email to