Parse hexadecimal and octal strings correctly
authorSiddhesh Poyarekar <siddhesh@redhat.com>
Wed, 25 Apr 2012 06:22:39 +0000 (11:52 +0530)
committerSiddhesh Poyarekar <siddhesh@redhat.com>
Wed, 25 Apr 2012 06:57:03 +0000 (12:27 +0530)
The current implementation of __strtoul_internal seems to only pretend
to support hex and octal strings by detecting a preceding 0x or 0 and
marking base as 8 or 16. When it comes to the actual processing of the
string, it only considers numeric values within, thus breaking hex
values that may have [a-f] in them. Fixed with this commit.

ChangeLog
elf/dl-minimal.c

index 0f558fe..1a1d23a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2012-04-25  Siddhesh Poyarekar  <siddhesh@redhat.com>
+           Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+       * elf/dl-minimal.c (__strtoul_internal): Parse hexadecimal and octal
+       strings correctly.
+
 2012-04-25  Chung-Lin Tang  <cltang@codesourcery.com>
 
        * sysdeps/sh/memcpy.S: Remove include of endian.h, change
index 316de99..4a97f56 100644 (file)
@@ -1,6 +1,5 @@
 /* Minimal replacements for basic facilities used in the dynamic linker.
-   Copyright (C) 1995-1998,2000-2002,2004-2006,2007,2009
-   Free Software Foundation, Inc.
+   Copyright (C) 1995-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -232,6 +231,7 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
 {
   unsigned long int result = 0;
   long int sign = 1;
+  unsigned max_digit;
 
   while (*nptr == ' ' || *nptr == '\t')
     ++nptr;
@@ -253,6 +253,7 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
 
   assert (base == 0);
   base = 10;
+  max_digit = 9;
   if (*nptr == '0')
     {
       if (nptr[1] == 'x' || nptr[1] == 'X')
@@ -261,14 +262,31 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
          nptr += 2;
        }
       else
-       base = 8;
+       {
+         base = 8;
+         max_digit = 7;
+       }
     }
 
-  while (*nptr >= '0' && *nptr <= '9')
+  while (1)
     {
-      unsigned long int digval = *nptr - '0';
-      if (result > ULONG_MAX / 10
-         || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
+      unsigned long int digval;
+      if (*nptr >= '0' && *nptr <= '0' + max_digit)
+        digval = *nptr - '0';
+      else if (base == 16)
+        {
+         if (*nptr >= 'a' && *nptr <= 'f')
+           digval = *nptr - 'a' + 10;
+         else if (*nptr >= 'A' && *nptr <= 'F')
+           digval = *nptr - 'A' + 10;
+         else
+           break;
+       }
+      else
+        break;
+
+      if (result > ULONG_MAX / base
+         || (result == ULONG_MAX / base && digval > ULONG_MAX % base))
        {
          errno = ERANGE;
          if (endptr != NULL)