aboutsummaryrefslogtreecommitdiff
path: root/binutils/dwarf.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-07-10 09:34:30 +0930
committerAlan Modra <amodra@gmail.com>2021-07-10 13:23:54 +0930
commit9039747fb4863c13eaf07f84bb28d50660fb8d85 (patch)
tree1d5385789086f82eb6db07ccbb2a12e18eaf5eba /binutils/dwarf.c
parent34c54daa337da9fadf87d2706d6a590ae1f88f4d (diff)
downloadgdb-9039747fb4863c13eaf07f84bb28d50660fb8d85.zip
gdb-9039747fb4863c13eaf07f84bb28d50660fb8d85.tar.gz
gdb-9039747fb4863c13eaf07f84bb28d50660fb8d85.tar.bz2
PR28069, assertion fail in dwarf.c:display_discr_list
We shouldn't be asserting on anything to do with leb128 values, or reporting file and line numbers when something unexpected happens. leb128 data is of indeterminate length, perfect for fuzzer mayhem. It would only make sense to assert or report dwarf.c/readelf.c source lines if the code had already sized and sanity checked the leb128 values. After removing the assertions, the testcase then gave: <37> DW_AT_discr_list : 5 byte block: 0 0 0 0 0 (label 0, label 0, label 0, label 0, <corrupt> readelf: Warning: corrupt discr_list - unrecognized discriminant byte 0x5 <3d> DW_AT_encoding : 0 (void) <3e> DW_AT_identifier_case: 0 (case_sensitive) <3f> DW_AT_virtuality : 0 (none) <40> DW_AT_decimal_sign: 5 (trailing separate) So the DW_AT_discr_list was showing more data than just the 5 byte block. That happened due to "end" pointing a long way past the end of block, and uvalue decrementing past zero on one of the leb128 bytes. PR 28069 * dwarf.c (display_discr_list): Remove assertions. Delete "end" parameter, use initial "data" pointer as the end. Formatting. Don't count down bytes as they are read. (read_and_display_attr_value): Adjust display_discr_list call. (read_and_print_leb128): Don't pass __FILE__ and __LINE__ to report_leb_status. * dwarf.h (report_leb_status): Don't report file and line numbers. Delete file and lnum parameters, (READ_ULEB, READ_SLEB): Adjust.
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r--binutils/dwarf.c24
1 files changed, 8 insertions, 16 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index ad1ee97..fbd5d6a 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -2280,7 +2280,7 @@ read_and_print_leb128 (unsigned char *data,
int status;
dwarf_vma val = read_leb128 (data, end, is_signed, bytes_read, &status);
if (status != 0)
- report_leb_status (status, __FILE__, __LINE__);
+ report_leb_status (status);
else
printf ("%s", dwarf_vmatoa (is_signed ? "d" : "u", val));
}
@@ -2289,9 +2289,10 @@ static void
display_discr_list (unsigned long form,
dwarf_vma uvalue,
unsigned char * data,
- unsigned const char * end,
int level)
{
+ unsigned char *end = data;
+
if (uvalue == 0)
{
printf ("[default]");
@@ -2320,41 +2321,32 @@ display_discr_list (unsigned long form,
return;
}
- bool is_signed =
- (level > 0 && level <= MAX_CU_NESTING)
- ? level_type_signed [level - 1] : false;
+ bool is_signed = (level > 0 && level <= MAX_CU_NESTING
+ ? level_type_signed [level - 1] : false);
printf ("(");
- while (uvalue)
+ while (data < end)
{
unsigned char discriminant;
unsigned int bytes_read;
SAFE_BYTE_GET_AND_INC (discriminant, data, 1, end);
- -- uvalue;
- assert (uvalue > 0);
switch (discriminant)
{
case DW_DSC_label:
printf ("label ");
read_and_print_leb128 (data, & bytes_read, end, is_signed);
- assert (bytes_read <= uvalue && bytes_read > 0);
- uvalue -= bytes_read;
data += bytes_read;
break;
case DW_DSC_range:
printf ("range ");
read_and_print_leb128 (data, & bytes_read, end, is_signed);
- assert (bytes_read <= uvalue && bytes_read > 0);
- uvalue -= bytes_read;
data += bytes_read;
printf ("..");
read_and_print_leb128 (data, & bytes_read, end, is_signed);
- assert (bytes_read <= uvalue && bytes_read > 0);
- uvalue -= bytes_read;
data += bytes_read;
break;
@@ -2365,7 +2357,7 @@ display_discr_list (unsigned long form,
return;
}
- if (uvalue)
+ if (data < end)
printf (", ");
}
@@ -3230,7 +3222,7 @@ read_and_display_attr_value (unsigned long attribute,
case DW_AT_discr_list:
printf ("\t");
- display_discr_list (form, uvalue, data, end, level);
+ display_discr_list (form, uvalue, data, level);
break;
case DW_AT_frame_base: