aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom de Vries <tdevries@suse.de>2022-06-04 13:17:33 +0200
committerTom de Vries <tdevries@suse.de>2022-06-04 13:17:33 +0200
commit999f7adc21cdcef5b606d2529068121dc6032b18 (patch)
treea9816ef9c80aa8cc631f57ae44f4cd107c13e93e
parent1390b65a1b93f75cdd4165f190b4a95b93add66e (diff)
downloadgdb-999f7adc21cdcef5b606d2529068121dc6032b18.zip
gdb-999f7adc21cdcef5b606d2529068121dc6032b18.tar.gz
gdb-999f7adc21cdcef5b606d2529068121dc6032b18.tar.bz2
[gdb/m2] Fix UB and literal truncation
Rewrite parse_number to use ULONGEST instead of LONGEST, to fix UB errors as mentioned in PR29163. Furthermore, make sure we error out on overflow instead of truncating in all cases. Tested on x86_64-linux, with a build with --enable-targets=all. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29163
-rw-r--r--gdb/m2-exp.y47
-rw-r--r--gdb/testsuite/gdb.base/parse_number.exp3
2 files changed, 24 insertions, 26 deletions
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index 85bac11..d3e917b 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -582,12 +582,11 @@ static int
parse_number (int olen)
{
const char *p = pstate->lexptr;
- LONGEST n = 0;
- LONGEST prevn = 0;
+ ULONGEST n = 0;
+ ULONGEST prevn = 0;
int c,i,ischar=0;
int base = input_radix;
int len = olen;
- int unsigned_p = number_sign == 1 ? 1 : 0;
if(p[len-1] == 'H')
{
@@ -639,16 +638,11 @@ parse_number (int olen)
n+=i;
if(i >= base)
return ERROR;
- if(!unsigned_p && number_sign == 1 && (prevn >= n))
- unsigned_p=1; /* Try something unsigned */
- /* Don't do the range check if n==i and i==0, since that special
- case will give an overflow error. */
- if(RANGE_CHECK && n!=i && i)
- {
- if((unsigned_p && (unsigned)prevn >= (unsigned)n) ||
- ((!unsigned_p && number_sign==-1) && -prevn <= -n))
- range_error (_("Overflow on numeric constant."));
- }
+ if (n == 0 && prevn == 0)
+ ;
+ else if (RANGE_CHECK && prevn >= n)
+ range_error (_("Overflow on numeric constant."));
+
prevn=n;
}
@@ -661,17 +655,22 @@ parse_number (int olen)
yylval.ulval = n;
return CHAR;
}
- else if ( unsigned_p && number_sign == 1)
- {
- yylval.ulval = n;
- return UINT;
- }
- else if((unsigned_p && (n<0))) {
- range_error (_("Overflow on numeric constant -- number too large."));
- /* But, this can return if range_check == range_warn. */
- }
- yylval.lval = n;
- return INT;
+
+ int int_bits = gdbarch_int_bit (pstate->gdbarch ());
+ bool have_signed = number_sign == -1;
+ bool have_unsigned = number_sign == 1;
+ if (have_signed && fits_in_type (number_sign, n, int_bits, true))
+ {
+ yylval.lval = n;
+ return INT;
+ }
+ else if (have_unsigned && fits_in_type (number_sign, n, int_bits, false))
+ {
+ yylval.ulval = n;
+ return UINT;
+ }
+ else
+ error (_("Overflow on numeric constant."));
}
diff --git a/gdb/testsuite/gdb.base/parse_number.exp b/gdb/testsuite/gdb.base/parse_number.exp
index 4189cca..6e00912 100644
--- a/gdb/testsuite/gdb.base/parse_number.exp
+++ b/gdb/testsuite/gdb.base/parse_number.exp
@@ -161,8 +161,7 @@ proc parse_number { lang n } {
return [list "CARDINAL" $n]
} else {
# Overflow.
- # Some truncated value or re_overflow, should be re_overflow.
- return [list ($re_overflow|CARDINAL|INTEGER) ($re_overflow|$any)]
+ return [list $re_overflow $re_overflow]
}
} elseif { $lang == "fortran" } {
if { [fits_in_type $n $int_bits s] } {