dwarf2.c: read_abbrevs fail cleanup, and offset checking

read_section does offset checking, reporting an error on out of
bounds.  There's no need to duplicate the check in functions calling
read_section.  Also, I spotted a place where a pointer difference
expression was being cast to unsigned int, possibly truncating
relevant bits on a 64-bit host.

	* dwarf2.c (read_indirect_string): Don't duplicate offset check
	done in read_section.
	(read_indirect_line_string): Likewise.
	(read_alt_indirect_string): Likewise.
	(read_alt_indirect_ref): Likewise.
	(read_abbrevs): Likewise.  Free memory on all failure paths.
	Use correct unsigned type for pointer difference comparison.
This commit is contained in:
Alan Modra
2019-11-30 09:12:29 +10:30
parent 1b8e12713b
commit 019cc8758a
2 changed files with 32 additions and 29 deletions

View File

@ -1,3 +1,13 @@
2019-12-03 Alan Modra <amodra@gmail.com>
* dwarf2.c (read_indirect_string): Don't duplicate offset check
done in read_section.
(read_indirect_line_string): Likewise.
(read_alt_indirect_string): Likewise.
(read_alt_indirect_ref): Likewise.
(read_abbrevs): Likewise. Free memory on all failure paths.
Use correct unsigned type for pointer difference comparison.
2019-12-03 Alan Modra <amodra@gmail.com> 2019-12-03 Alan Modra <amodra@gmail.com>
* dwarf2.c (struct dwarf2_debug): Update comments. Remove sec * dwarf2.c (struct dwarf2_debug): Update comments. Remove sec

View File

@ -721,8 +721,6 @@ read_indirect_string (struct comp_unit * unit,
&stash->dwarf_str_buffer, &stash->dwarf_str_size)) &stash->dwarf_str_buffer, &stash->dwarf_str_size))
return NULL; return NULL;
if (offset >= stash->dwarf_str_size)
return NULL;
str = (char *) stash->dwarf_str_buffer + offset; str = (char *) stash->dwarf_str_buffer + offset;
if (*str == '\0') if (*str == '\0')
return NULL; return NULL;
@ -760,8 +758,6 @@ read_indirect_line_string (struct comp_unit * unit,
&stash->dwarf_line_str_size)) &stash->dwarf_line_str_size))
return NULL; return NULL;
if (offset >= stash->dwarf_line_str_size)
return NULL;
str = (char *) stash->dwarf_line_str_buffer + offset; str = (char *) stash->dwarf_line_str_buffer + offset;
if (*str == '\0') if (*str == '\0')
return NULL; return NULL;
@ -825,8 +821,6 @@ read_alt_indirect_string (struct comp_unit * unit,
&stash->alt_dwarf_str_size)) &stash->alt_dwarf_str_size))
return NULL; return NULL;
if (offset >= stash->alt_dwarf_str_size)
return NULL;
str = (char *) stash->alt_dwarf_str_buffer + offset; str = (char *) stash->alt_dwarf_str_buffer + offset;
if (*str == '\0') if (*str == '\0')
return NULL; return NULL;
@ -874,8 +868,6 @@ read_alt_indirect_ref (struct comp_unit * unit,
&stash->alt_dwarf_info_size)) &stash->alt_dwarf_info_size))
return NULL; return NULL;
if (offset >= stash->alt_dwarf_info_size)
return NULL;
return stash->alt_dwarf_info_buffer + offset; return stash->alt_dwarf_info_buffer + offset;
} }
@ -963,9 +955,6 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
&stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size)) &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
return NULL; return NULL;
if (offset >= stash->dwarf_abbrev_size)
return NULL;
amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt); abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt);
if (abbrevs == NULL) if (abbrevs == NULL)
@ -983,7 +972,7 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
amt = sizeof (struct abbrev_info); amt = sizeof (struct abbrev_info);
cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt); cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt);
if (cur_abbrev == NULL) if (cur_abbrev == NULL)
return NULL; goto fail;
/* Read in abbrev header. */ /* Read in abbrev header. */
cur_abbrev->number = abbrev_number; cur_abbrev->number = abbrev_number;
@ -1025,21 +1014,7 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
amt *= sizeof (struct attr_abbrev); amt *= sizeof (struct attr_abbrev);
tmp = (struct attr_abbrev *) bfd_realloc (cur_abbrev->attrs, amt); tmp = (struct attr_abbrev *) bfd_realloc (cur_abbrev->attrs, amt);
if (tmp == NULL) if (tmp == NULL)
{ goto fail;
size_t i;
for (i = 0; i < ABBREV_HASH_SIZE; i++)
{
struct abbrev_info *abbrev = abbrevs[i];
while (abbrev)
{
free (abbrev->attrs);
abbrev = abbrev->next;
}
}
return NULL;
}
cur_abbrev->attrs = tmp; cur_abbrev->attrs = tmp;
} }
@ -1063,7 +1038,7 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
already read (which means we are about to read the abbreviations already read (which means we are about to read the abbreviations
for the next compile unit) or if the end of the abbreviation for the next compile unit) or if the end of the abbreviation
table is reached. */ table is reached. */
if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer) if ((size_t) (abbrev_ptr - stash->dwarf_abbrev_buffer)
>= stash->dwarf_abbrev_size) >= stash->dwarf_abbrev_size)
break; break;
abbrev_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr, abbrev_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr,
@ -1072,8 +1047,26 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
if (lookup_abbrev (abbrev_number, abbrevs) != NULL) if (lookup_abbrev (abbrev_number, abbrevs) != NULL)
break; break;
} }
return abbrevs; return abbrevs;
fail:
if (abbrevs != NULL)
{
size_t i;
for (i = 0; i < ABBREV_HASH_SIZE; i++)
{
struct abbrev_info *abbrev = abbrevs[i];
while (abbrev)
{
free (abbrev->attrs);
abbrev = abbrev->next;
}
}
free (abbrevs);
}
return NULL;
} }
/* Returns true if the form is one which has a string value. */ /* Returns true if the form is one which has a string value. */