PR29230, segv in lookup_symbol_in_variable_table

The PR23230 testcase uses indexed strings without specifying
SW_AT_str_offsets_base.  In this case we left u.str with garbage (from
u.val) which then led to a segfault when attempting to access the
string.  Fix that by clearing u.str.  The patch also adds missing
sanity checks in the recently committed read_indexed_address and
read_indexed_string functions.

	PR 29230
	* dwarf2.c (read_indexed_address): Return uint64_t.  Sanity check idx.
	(read_indexed_string): Use uint64_t for str_offset.  Sanity check idx.
	(read_attribute_value): Clear u.str for indexed string forms when
	DW_AT_str_offsets_base is not yet read or missing.
This commit is contained in:
Alan Modra
2022-06-14 12:46:42 +09:30
parent dac0515d82
commit 31d6c13def

View File

@ -1353,13 +1353,13 @@ is_addrx_form (enum dwarf_form form)
/* Returns the address in .debug_addr section using DW_AT_addr_base. /* Returns the address in .debug_addr section using DW_AT_addr_base.
Used to implement DW_FORM_addrx*. */ Used to implement DW_FORM_addrx*. */
static bfd_vma static uint64_t
read_indexed_address (uint64_t idx, struct comp_unit *unit) read_indexed_address (uint64_t idx, struct comp_unit *unit)
{ {
struct dwarf2_debug *stash = unit->stash; struct dwarf2_debug *stash = unit->stash;
struct dwarf2_debug_file *file = unit->file; struct dwarf2_debug_file *file = unit->file;
size_t addr_base = unit->dwarf_addr_offset;
bfd_byte *info_ptr; bfd_byte *info_ptr;
size_t offset;
if (stash == NULL) if (stash == NULL)
return 0; return 0;
@ -1369,12 +1369,23 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit)
&file->dwarf_addr_buffer, &file->dwarf_addr_size)) &file->dwarf_addr_buffer, &file->dwarf_addr_size))
return 0; return 0;
info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size; if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
return 0;
offset += unit->dwarf_addr_offset;
if (offset < unit->dwarf_addr_offset
|| offset > file->dwarf_addr_size
|| file->dwarf_addr_size - offset < unit->offset_size)
return 0;
info_ptr = file->dwarf_addr_buffer + offset;
if (unit->offset_size == 4) if (unit->offset_size == 4)
return bfd_get_32 (unit->abfd, info_ptr); return bfd_get_32 (unit->abfd, info_ptr);
else else if (unit->offset_size == 8)
return bfd_get_64 (unit->abfd, info_ptr); return bfd_get_64 (unit->abfd, info_ptr);
else
return 0;
} }
/* Returns the string using DW_AT_str_offsets_base. /* Returns the string using DW_AT_str_offsets_base.
@ -1385,7 +1396,8 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
struct dwarf2_debug *stash = unit->stash; struct dwarf2_debug *stash = unit->stash;
struct dwarf2_debug_file *file = unit->file; struct dwarf2_debug_file *file = unit->file;
bfd_byte *info_ptr; bfd_byte *info_ptr;
unsigned long str_offset; uint64_t str_offset;
size_t offset;
if (stash == NULL) if (stash == NULL)
return NULL; return NULL;
@ -1401,15 +1413,26 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
&file->dwarf_str_offsets_size)) &file->dwarf_str_offsets_size))
return NULL; return NULL;
info_ptr = (file->dwarf_str_offsets_buffer if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
+ unit->dwarf_str_offset return NULL;
+ idx * unit->offset_size);
offset += unit->dwarf_str_offset;
if (offset < unit->dwarf_str_offset
|| offset > file->dwarf_str_offsets_size
|| file->dwarf_str_offsets_size - offset < unit->offset_size)
return NULL;
info_ptr = file->dwarf_str_offsets_buffer + offset;
if (unit->offset_size == 4) if (unit->offset_size == 4)
str_offset = bfd_get_32 (unit->abfd, info_ptr); str_offset = bfd_get_32 (unit->abfd, info_ptr);
else else if (unit->offset_size == 8)
str_offset = bfd_get_64 (unit->abfd, info_ptr); str_offset = bfd_get_64 (unit->abfd, info_ptr);
else
return NULL;
if (str_offset >= file->dwarf_str_size)
return NULL;
return (const char *) file->dwarf_str_buffer + str_offset; return (const char *) file->dwarf_str_buffer + str_offset;
} }
@ -1534,27 +1557,37 @@ read_attribute_value (struct attribute * attr,
is not yet read. */ is not yet read. */
if (unit->dwarf_str_offset != 0) if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit); attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
else
attr->u.str = NULL;
break; break;
case DW_FORM_strx2: case DW_FORM_strx2:
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end); attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_str_offset != 0) if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit); attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
else
attr->u.str = NULL;
break; break;
case DW_FORM_strx3: case DW_FORM_strx3:
attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end); attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_str_offset != 0) if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit); attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
else
attr->u.str = NULL;
break; break;
case DW_FORM_strx4: case DW_FORM_strx4:
attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end); attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_str_offset != 0) if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit); attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
else
attr->u.str = NULL;
break; break;
case DW_FORM_strx: case DW_FORM_strx:
attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr, attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
false, info_ptr_end); false, info_ptr_end);
if (unit->dwarf_str_offset != 0) if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit); attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
else
attr->u.str = NULL;
break; break;
case DW_FORM_exprloc: case DW_FORM_exprloc:
case DW_FORM_block: case DW_FORM_block: