]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
all: improve parsing of numeric arguments
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 22 Oct 2019 21:55:24 +0000 (14:55 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 22 Oct 2019 22:04:43 +0000 (15:04 -0700)
This addresses a longstanding "update all callers" FIXME in
lib/xstrtol.c, by having programs check that numbers do not
have unknown suffixes.  The problem was also reported for
'shuf' by my student Maggie Huang while reimplementing a shuf
subset in Python as an exercise in UCLA Computer Science 35L:
https://web.cs.ucla.edu/classes/fall19/cs35L/assign/assign3.html
This patch also improves the portability of the code to unusual
platforms where ULONG_MAX < SIZE_MAX.
* NEWS: Mention user-visible changes.
* src/chgrp.c (parse_group):
* src/chroot.c (parse_additional_groups):
* src/du.c (main):
* src/install.c (get_ids):
* src/join.c (string_to_join_field):
* src/ls.c (decode_switches):
* src/md5sum.c (split_3):
* src/shuf.c (main):
* src/sort.c (specify_nthreads):
* src/uniq.c (size_opt, main):
Use uintmax_t instead of unsigned long, for portability
to oddball platforms where unsigned long is not wide enough.
* src/du.c (main):
* src/expr.c (mpz_init_set_str) [!HAVE_GMP]:
* src/install.c (get_ids):
* src/ls.c (decode_switches):
* src/mknod.c (main):
* src/ptx.c (main):
* src/shuf.c (main):
* src/sort.c (specify_nmerge, specify_nthreads):
Reject numbers with suffixes.
* src/md5sum.c (split_3): Simplify.

14 files changed:
NEWS
src/chgrp.c
src/chroot.c
src/du.c
src/expr.c
src/install.c
src/join.c
src/ls.c
src/md5sum.c
src/mknod.c
src/ptx.c
src/shuf.c
src/sort.c
src/uniq.c

diff --git a/NEWS b/NEWS
index 476c02aedc3b4f881d03e4d0b6f77d55f70ccaac..300a799ae40fced943fc7d2c468763c3e0cd2cdf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -43,6 +43,13 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Changes in behavior
 
+  Several programs now check that numbers end properly.  For example,
+  'du -d 1x' now reports an error instead of silently ignoring the 'x'.
+  Affected programs and options include du -d, expr's numeric operands
+  on non-GMP builds, install -g and -o, ls's TABSIZE environment
+  variable, mknod b and c, ptx -g and -w, shuf -n, and sort --batch-size
+  and --parallel.
+
   date now parses military time zones in accordance with common usage:
     "A" to "M"  are equivalent to UTC+1 to UTC+12
     "N" to "Y"  are equivalent to UTC-1 to UTC-12
index dfd39ae5eeb481fa3d607ae5d062ef54a0bb5242..b7393eef6b901731b9fe93e35aa93f507df12462 100644 (file)
@@ -87,8 +87,8 @@ parse_group (const char *name)
         gid = grp->gr_gid;
       else
         {
-          unsigned long int tmp;
-          if (! (xstrtoul (name, NULL, 10, &tmp, "") == LONGINT_OK
+          uintmax_t tmp;
+          if (! (xstrtoumax (name, NULL, 10, &tmp, "") == LONGINT_OK
                  && tmp <= GID_T_MAX))
             die (EXIT_FAILURE, 0, _("invalid group: %s"),
                  quote (name));
index 42ea5fa927c82c4a3a83028a5640c5f3ccdde738..ea55e75272c30f365d821a1c94ce3a6ff54f8a1c 100644 (file)
@@ -106,9 +106,10 @@ parse_additional_groups (char const *groups, GETGROUPS_T **pgids,
   for (tmp = strtok (buffer, ","); tmp; tmp = strtok (NULL, ","))
     {
       struct group *g;
-      unsigned long int value;
+      uintmax_t value;
 
-      if (xstrtoul (tmp, NULL, 10, &value, "") == LONGINT_OK && value <= MAXGID)
+      if (xstrtoumax (tmp, NULL, 10, &value, "") == LONGINT_OK
+          && value <= MAXGID)
         {
           while (isspace (to_uchar (*tmp)))
             tmp++;
index 43c3481593242b3391ee9d4a7ab7cfc664196b5d..a44b22e46b621862397b29b14142c73fc1da0b26 100644 (file)
--- a/src/du.c
+++ b/src/du.c
@@ -807,12 +807,12 @@ main (int argc, char **argv)
 
         case 'd':              /* --max-depth=N */
           {
-            unsigned long int tmp_ulong;
-            if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
-                && tmp_ulong <= SIZE_MAX)
+            uintmax_t tmp;
+            if (xstrtoumax (optarg, NULL, 0, &tmp, "") == LONGINT_OK
+                && tmp <= SIZE_MAX)
               {
                 max_depth_specified = true;
-                max_depth = tmp_ulong;
+                max_depth = tmp;
               }
             else
               {
index 3ce61b2036936baac3898b15bf3015c4d8592bbf..08d7277ecd66965e8017d0951113b2f3aeb367fe 100644 (file)
@@ -60,7 +60,7 @@ static void mpz_init_set_ui (mpz_t z, unsigned long int i) { z[0] = i; }
 static int
 mpz_init_set_str (mpz_t z, char *s, int base)
 {
-  return xstrtoimax (s, NULL, base, z, NULL) == LONGINT_OK ? 0 : -1;
+  return xstrtoimax (s, NULL, base, z, "") == LONGINT_OK ? 0 : -1;
 }
 static void
 mpz_add (mpz_t r, mpz_t a0, mpz_t b0)
index bde69c994df0f5567aa803ed3f2d11537729ee08..8b02be9652b4f19efc62085018f1dac85d629a39 100644 (file)
@@ -583,8 +583,8 @@ get_ids (void)
       pw = getpwnam (owner_name);
       if (pw == NULL)
         {
-          unsigned long int tmp;
-          if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
+          uintmax_t tmp;
+          if (xstrtoumax (owner_name, NULL, 0, &tmp, "") != LONGINT_OK
               || UID_T_MAX < tmp)
             die (EXIT_FAILURE, 0, _("invalid user %s"),
                  quote (owner_name));
@@ -602,8 +602,8 @@ get_ids (void)
       gr = getgrnam (group_name);
       if (gr == NULL)
         {
-          unsigned long int tmp;
-          if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
+          uintmax_t tmp;
+          if (xstrtoumax (group_name, NULL, 0, &tmp, "") != LONGINT_OK
               || GID_T_MAX < tmp)
             die (EXIT_FAILURE, 0, _("invalid group %s"),
                  quote (group_name));
index dd0ce42bcdfbebe4d89f412ec284bf2493d5ec7e..64156a22cd5365c549b92f4f34042cfe21ac5d6e 100644 (file)
@@ -839,10 +839,9 @@ static size_t
 string_to_join_field (char const *str)
 {
   size_t result;
-  unsigned long int val;
-  verify (SIZE_MAX <= ULONG_MAX);
+  uintmax_t val;
 
-  strtol_error s_err = xstrtoul (str, NULL, 10, &val, "");
+  strtol_error s_err = xstrtoumax (str, NULL, 10, &val, "");
   if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val))
     val = SIZE_MAX;
   else if (s_err != LONGINT_OK || val == 0)
index 034087f264756fc3426aa0818ca11ebfb51a167b..d02653b4890544174072507143ddff8c8ed8f7b5 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -1902,18 +1902,15 @@ decode_switches (int argc, char **argv)
     tabsize = 8;
     if (p)
       {
-        unsigned long int tmp_ulong;
-        if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
-            && tmp_ulong <= SIZE_MAX)
-          {
-            tabsize = tmp_ulong;
-          }
+        uintmax_t tmp;
+        if (xstrtoumax (p, NULL, 0, &tmp, "") == LONGINT_OK
+            && tmp <= SIZE_MAX)
+          tabsize = tmp;
         else
-          {
-            error (0, 0,
-             _("ignoring invalid tab size in environment variable TABSIZE: %s"),
-                   quote (p));
-          }
+          error (0, 0,
+                 _("ignoring invalid tab size in environment variable TABSIZE:"
+                   " %s"),
+                 quote (p));
       }
   }
 
index f75b6de02b911c8f83980773c8f28d8966b5081d..de847ccb2116f5a3f7a922c7076408c31fd46968 100644 (file)
@@ -450,26 +450,23 @@ split_3 (char *s, size_t s_len,
       ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0);
       if (algo < 0)
         return false;
-      else
-        b2_algorithm = algo;
+      b2_algorithm = algo;
       if (openssl_format)
         s[--i] = '(';
 
+      b2_length = blake2_max_len[b2_algorithm] * 8;
       if (length_specified)
         {
-          unsigned long int tmp_ulong;
-          if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
-              && 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8
-              && tmp_ulong % 8 == 0)
-            b2_length = tmp_ulong;
-          else
+          uintmax_t length;
+          char *siend;
+          if (! (xstrtoumax (s + i, &siend, 0, &length, NULL) == LONGINT_OK
+                 && 0 < length && length <= b2_length
+                 && length % 8 == 0))
             return false;
 
-          while (ISDIGIT (s[i]))
-            ++i;
+          i = siend - s;
+          b2_length = length;
         }
-      else
-        b2_length = blake2_max_len[b2_algorithm] * 8;
 
       digest_hex_bytes = b2_length / 4;
 #endif
index 7f7cbc7394f1f6f066d7429e4cfb56a4b5ea8e23..3f430af46a46eb96b23198d9fef0ea5b730c67ff 100644 (file)
@@ -230,12 +230,12 @@ main (int argc, char **argv)
         uintmax_t i_major, i_minor;
         dev_t device;
 
-        if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK
+        if (xstrtoumax (s_major, NULL, 0, &i_major, "") != LONGINT_OK
             || i_major != (major_t) i_major)
           die (EXIT_FAILURE, 0,
                _("invalid major device number %s"), quote (s_major));
 
-        if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK
+        if (xstrtoumax (s_minor, NULL, 0, &i_minor, "") != LONGINT_OK
             || i_minor != (minor_t) i_minor)
           die (EXIT_FAILURE, 0,
                _("invalid minor device number %s"), quote (s_minor));
index 3f2344055d646b0df1d2deeec3ba0d1848344a07..779b78c900d2830e276a04cd0054b9d177833e10 100644 (file)
--- a/src/ptx.c
+++ b/src/ptx.c
@@ -1940,7 +1940,7 @@ main (int argc, char **argv)
         case 'g':
           {
             intmax_t tmp;
-            if (! (xstrtoimax (optarg, NULL, 0, &tmp, NULL) == LONGINT_OK
+            if (! (xstrtoimax (optarg, NULL, 0, &tmp, "") == LONGINT_OK
                    && 0 < tmp && tmp <= PTRDIFF_MAX))
               die (EXIT_FAILURE, 0, _("invalid gap width: %s"),
                    quote (optarg));
@@ -1967,7 +1967,7 @@ main (int argc, char **argv)
         case 'w':
           {
             intmax_t tmp;
-            if (! (xstrtoimax (optarg, NULL, 0, &tmp, NULL) == LONGINT_OK
+            if (! (xstrtoimax (optarg, NULL, 0, &tmp, "") == LONGINT_OK
                    && 0 < tmp && tmp <= PTRDIFF_MAX))
               die (EXIT_FAILURE, 0, _("invalid line width: %s"),
                    quote (optarg));
index 6a1aa0158e1cc1acbcb2622ca24bb862d86116be..37a5a5554ffe66c50049bb4ef6ea2c80c3007581 100644 (file)
@@ -440,8 +440,8 @@ main (int argc, char **argv)
 
       case 'n':
         {
-          unsigned long int argval;
-          strtol_error e = xstrtoul (optarg, NULL, 10, &argval, NULL);
+          uintmax_t argval;
+          strtol_error e = xstrtoumax (optarg, NULL, 10, &argval, "");
 
           if (e == LONGINT_OK)
             head_lines = MIN (head_lines, argval);
index 360a1f140c71d6292a5d91d6edda848bc2576caa..b2336894f0ae242a2b9ade296331188819eb4e36 100644 (file)
@@ -1330,7 +1330,7 @@ specify_nmerge (int oi, char c, char const *s)
 {
   uintmax_t n;
   struct rlimit rlimit;
-  enum strtol_error e = xstrtoumax (s, NULL, 10, &n, NULL);
+  enum strtol_error e = xstrtoumax (s, NULL, 10, &n, "");
 
   /* Try to find out how many file descriptors we'll be able
      to open.  We need at least nmerge + 3 (STDIN_FILENO,
@@ -1443,8 +1443,8 @@ specify_sort_size (int oi, char c, char const *s)
 static size_t
 specify_nthreads (int oi, char c, char const *s)
 {
-  unsigned long int nthreads;
-  enum strtol_error e = xstrtoul (s, NULL, 10, &nthreads, "");
+  uintmax_t nthreads;
+  enum strtol_error e = xstrtoumax (s, NULL, 10, &nthreads, "");
   if (e == LONGINT_OVERFLOW)
     return SIZE_MAX;
   if (e != LONGINT_OK)
index 9600ec09467715c9d7ef2e264eaa8bfc801d52f7..83647362411738010686be8a7ff7d9c9f00402e6 100644 (file)
@@ -240,10 +240,9 @@ strict_posix2 (void)
 static size_t
 size_opt (char const *opt, char const *msgid)
 {
-  unsigned long int size;
-  verify (SIZE_MAX <= ULONG_MAX);
+  uintmax_t size;
 
-  switch (xstrtoul (opt, NULL, 10, &size, ""))
+  switch (xstrtoumax (opt, NULL, 10, &size, ""))
     {
     case LONGINT_OK:
     case LONGINT_OVERFLOW:
@@ -539,10 +538,10 @@ main (int argc, char **argv)
         {
         case 1:
           {
-            unsigned long int size;
+            uintmax_t size;
             if (optarg[0] == '+'
                 && ! strict_posix2 ()
-                && xstrtoul (optarg, NULL, 10, &size, "") == LONGINT_OK
+                && xstrtoumax (optarg, NULL, 10, &size, "") == LONGINT_OK
                 && size <= SIZE_MAX)
               skip_chars = size;
             else if (nfiles == 2)