You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2020/11/12 14:09:24 UTC

[incubator-nuttx] branch master updated: libc/stdlib: Fix range check in strtoul(l)

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 1f5786f  libc/stdlib: Fix range check in strtoul(l)
1f5786f is described below

commit 1f5786f5eab6ca09b960c8595fb036f00216573e
Author: Peter Bee <bi...@xiaomi.com>
AuthorDate: Wed Nov 11 15:49:04 2020 +0800

    libc/stdlib: Fix range check in strtoul(l)
    
    The previous implementation of strtoul(l) is flawed. The range check
    assumed that when overflow happens, the truncated value is smaller than
    the original value. As a counter example, passing "10000000000" to
    strtol will not trigger ERANGE, but return a truncated value. This patch
    adds more accurate range checks.
    
    Change-Id: I239e034e390b4974157ed6efa17110f2e74904cf
    Signed-off-by: Peter Bee <bi...@xiaomi.com>
---
 libs/libc/stdlib/lib_strtoul.c  | 15 +++++++++------
 libs/libc/stdlib/lib_strtoull.c | 18 +++++++++++-------
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/libs/libc/stdlib/lib_strtoul.c b/libs/libc/stdlib/lib_strtoul.c
index 29ca5c4..1ee1de2 100644
--- a/libs/libc/stdlib/lib_strtoul.c
+++ b/libs/libc/stdlib/lib_strtoul.c
@@ -69,8 +69,9 @@
 unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base)
 {
   unsigned long accum = 0;
-  unsigned long prev;
+  unsigned long limit;
   int value;
+  int last_digit;
   char sign = 0;
 
   if (nptr)
@@ -98,22 +99,24 @@ unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base)
         }
       else
         {
+          limit = ULONG_MAX / base;
+          last_digit = ULONG_MAX % base;
+
           /* Accumulate each "digit" */
 
           while (lib_isbasedigit(*nptr, base, &value))
             {
-              prev = accum;
-              accum = accum * base + value;
-              nptr++;
-
               /* Check for overflow */
 
-              if (accum < prev)
+              if (accum > limit || (accum == limit && value > last_digit))
                 {
                   set_errno(ERANGE);
                   accum = ULONG_MAX;
                   break;
                 }
+
+              accum = accum * base + value;
+              nptr++;
             }
 
           if (sign == '-')
diff --git a/libs/libc/stdlib/lib_strtoull.c b/libs/libc/stdlib/lib_strtoull.c
index 4e27a1f..735e90c 100644
--- a/libs/libc/stdlib/lib_strtoull.c
+++ b/libs/libc/stdlib/lib_strtoull.c
@@ -68,11 +68,13 @@
  *
  ****************************************************************************/
 
-unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base)
+unsigned long long strtoull(FAR const char *nptr,
+                            FAR char **endptr, int base)
 {
   unsigned long long accum = 0;
-  unsigned long long prev;
+  unsigned long long limit;
   int value;
+  int last_digit;
   char sign = 0;
 
   if (nptr)
@@ -100,22 +102,24 @@ unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base)
         }
       else
         {
+          limit = ULLONG_MAX / base;
+          last_digit = ULLONG_MAX % base;
+
           /* Accumulate each "digit" */
 
           while (lib_isbasedigit(*nptr, base, &value))
             {
-              prev = accum;
-              accum = accum * base + value;
-              nptr++;
-
               /* Check for overflow */
 
-              if (accum < prev)
+              if (accum > limit || (accum == limit && value > last_digit))
                 {
                   set_errno(ERANGE);
                   accum = ULLONG_MAX;
                   break;
                 }
+
+              accum = accum * base + value;
+              nptr++;
             }
 
           if (sign == '-')