* bfd.c (bfd_scan_vma): Clamp overflows to max bfd_vma value.
[deliverable/binutils-gdb.git] / bfd / bfd.c
index 73bb17eb381db6a50f00eb6ed4157003ce5c12b3..57953837c16c834a2a25274a598fd188e547dac1 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1008,7 +1008,8 @@ DESCRIPTION
        in hex if a leading "0x" or "0X" is found, otherwise
        in octal if a leading zero is found, otherwise in decimal.
 
-       Overflow is not detected.
+       If the value would overflow, the maximum <<bfd_vma>> value is
+       returned.
 */
 
 bfd_vma
@@ -1018,48 +1019,64 @@ bfd_scan_vma (string, end, base)
      int base;
 {
   bfd_vma value;
-  int digit;
+  bfd_vma cutoff;
+  unsigned int cutlim;
+  int overflow;
 
   /* Let the host do it if possible.  */
   if (sizeof (bfd_vma) <= sizeof (unsigned long))
     return (bfd_vma) strtoul (string, (char **) end, base);
 
-  /* A negative base makes no sense, and we only need to go as high as hex.  */
-  if ((base < 0) || (base > 16))
-    return (bfd_vma) 0;
-
   if (base == 0)
     {
       if (string[0] == '0')
        {
          if ((string[1] == 'x') || (string[1] == 'X'))
            base = 16;
-         /* XXX should we also allow "0b" or "0B" to set base to 2?  */
          else
            base = 8;
        }
-      else
-       base = 10;
     }
 
-  if ((base == 16) &&
-      (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X')))
-    string += 2;
-  /* XXX should we also skip over "0b" or "0B" if base is 2?  */
+  if ((base < 2) || (base > 36))
+    base = 10;
+
+  if (base == 16
+      && string[0] == '0'
+      && (string[1] == 'x' || string[1] == 'X')
+      && ISXDIGIT (string[2]))
+    {
+      string += 2;
+    }
 
-/* Speed could be improved with a table like hex_value[] in gas.  */
-#define HEX_VALUE(c) \
-  (ISXDIGIT (c)                                                        \
-   ? (ISDIGIT (c)                                              \
-      ? (c - '0')                                              \
-      : (10 + c - (ISLOWER (c) ? 'a' : 'A')))                  \
-   : 42)
+  cutoff = (~ (bfd_vma) 0) / (bfd_vma) base;
+  cutlim = (~ (bfd_vma) 0) % (bfd_vma) base;
+  value = 0;
+  overflow = 0;
+  while (1)
+    {
+      unsigned int digit;
+
+      digit = *string;
+      if (ISDIGIT (digit))
+       digit = digit - '0';
+      else if (ISALPHA (digit))
+       digit = TOUPPER (digit) - 'A' + 10;
+      else
+       break;
+      if (digit >= (unsigned int) base)
+       break;
+      if (value > cutoff || (value == cutoff && digit > cutlim))
+       overflow = 1;
+      value = value * base + digit;
+      ++string;
+    }
 
-  for (value = 0; (digit = HEX_VALUE (* string)) < base; string ++)
-    value = value * base + digit;
+  if (overflow)
+    value = ~ (bfd_vma) 0;
 
-  if (end)
-    * end = string;
+  if (end != NULL)
+    *end = string;
 
   return value;
 }
This page took 0.025156 seconds and 4 git commands to generate.