[gdb/m2] Fix UB and literal truncation
authorTom de Vries <tdevries@suse.de>
Sat, 4 Jun 2022 11:17:33 +0000 (13:17 +0200)
committerTom de Vries <tdevries@suse.de>
Sat, 4 Jun 2022 11:17:33 +0000 (13:17 +0200)
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

gdb/m2-exp.y
gdb/testsuite/gdb.base/parse_number.exp

index 85bac11b8fb612ae33bb7bdad8e1c98ef0cc5569..d3e917bb8d732d989248092f813f04a8542f3c63 100644 (file)
@@ -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."));
 }
 
 
index 4189ccaf92c393a913b6d672a37c64048d519d5b..6e0091278a90ea8bd3bdb3756b69697fbf063076 100644 (file)
@@ -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] } {