Dynamic array size can be a loclist/locexpr (#512)
authorSeva Alekseyev <sevaa@yarxi.ru>
Mon, 16 Oct 2023 13:44:11 +0000 (09:44 -0400)
committerGitHub <noreply@github.com>
Mon, 16 Oct 2023 13:44:11 +0000 (06:44 -0700)
* Dynamic array size can be a loclist/locexpr

* False pos in is_loclist on ubound being  constant

elftools/dwarf/locationlists.py
test/test_dwarf_locationattr.py

index 6397738293e9fa636f3bcbb91182ef0c5d715907..ffdfde8b2999ff16bfaa681f1929c5adf11a701d 100644 (file)
@@ -329,14 +329,16 @@ class LocationParser(object):
                  attr.form in ('DW_FORM_data1', 'DW_FORM_data2', 'DW_FORM_data4', 'DW_FORM_data8') and
                  not attr.name == 'DW_AT_const_value') or
                 attr.form in ('DW_FORM_sec_offset', 'DW_FORM_loclistx')) and
-                not LocationParser._attribute_is_member_offset(attr, dwarf_version))
+                not LocationParser._attribute_is_constant(attr, dwarf_version))
     
     # Starting with DWARF3, DW_AT_data_member_location may contain an integer offset
     # instead of a location expression. Need to prevent false positives on attribute_has_location().
+    # As for DW_AT_upper_bound/DW_AT_count, we've seen it in form DW_FORM_locexpr in a V5 binary. usually it's a constant,
+    # but the constant sholdn't be misinterpreted as a loclist pointer.
     @staticmethod
-    def _attribute_is_member_offset(attr, dwarf_version):
-        return (dwarf_version >= 3 and
-            attr.name == 'DW_AT_data_member_location' and
+    def _attribute_is_constant(attr, dwarf_version):
+        return (((dwarf_version >= 3 and attr.name == 'DW_AT_data_member_location') or
+                 (attr.name in ('DW_AT_upper_bound', 'DW_AT_count'))) and
             attr.form in ('DW_FORM_data1', 'DW_FORM_data2', 'DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sdata', 'DW_FORM_udata'))
 
     @staticmethod
@@ -354,4 +356,6 @@ class LocationParser(object):
                                'DW_AT_call_target',
                                'DW_AT_call_target_clobbered',
                                'DW_AT_call_data_location',
-                               'DW_AT_call_data_value'))
+                               'DW_AT_call_data_value',
+                               'DW_AT_upper_bound',
+                               'DW_AT_count'))
index 6d764d2f309ab7534f4a21b2eeeead49ab2cc487..e3befc73795e62291cb88243404de7378e63a8ae 100644 (file)
@@ -35,6 +35,12 @@ class TestLocationAttrubute(unittest.TestCase):
         attr = AttributeValue(name='DW_AT_call_target', form='DW_FORM_exprloc', value=[80], raw_value=[80], offset=8509, indirection_length=0)
         self.assertTrue(LocationParser.attribute_has_location(attr, 5))
 
+        # This attribute came from the binary in issue #508
+        # DW_TAG_subrange_type at 0x45DEA
+        attr = AttributeValue(name='DW_AT_upper_bound', form='DW_FORM_exprloc', value=[163, 1, 94, 49, 28], raw_value=[163, 1, 94, 49, 28], offset=286191, indirection_length=0)
+        self.assertTrue(LocationParser.attribute_has_location(attr, 5))
+
+
 
 if __name__ == '__main__':
     unittest.main()
\ No newline at end of file