diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-10-22 14:55:24 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-10-22 15:04:43 -0700 |
commit | 04b136e29853a53a7885371526c4616303c39bcc (patch) | |
tree | 41a421cefc35d11b72537a37bfa2eeeb42a18c3b | |
parent | ed2db6886bc4dfa5be7c0a3a72a45024fdafe29f (diff) | |
download | coreutils-04b136e29853a53a7885371526c4616303c39bcc.tar.gz |
all: improve parsing of numeric arguments
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.
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | src/chgrp.c | 4 | ||||
-rw-r--r-- | src/chroot.c | 5 | ||||
-rw-r--r-- | src/du.c | 8 | ||||
-rw-r--r-- | src/expr.c | 2 | ||||
-rw-r--r-- | src/install.c | 8 | ||||
-rw-r--r-- | src/join.c | 5 | ||||
-rw-r--r-- | src/ls.c | 19 | ||||
-rw-r--r-- | src/md5sum.c | 21 | ||||
-rw-r--r-- | src/mknod.c | 4 | ||||
-rw-r--r-- | src/ptx.c | 4 | ||||
-rw-r--r-- | src/shuf.c | 4 | ||||
-rw-r--r-- | src/sort.c | 6 | ||||
-rw-r--r-- | src/uniq.c | 9 |
14 files changed, 53 insertions, 53 deletions
@@ -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 diff --git a/src/chgrp.c b/src/chgrp.c index dfd39ae5e..b7393eef6 100644 --- a/src/chgrp.c +++ b/src/chgrp.c @@ -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)); diff --git a/src/chroot.c b/src/chroot.c index 42ea5fa92..ea55e7527 100644 --- a/src/chroot.c +++ b/src/chroot.c @@ -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++; @@ -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 { diff --git a/src/expr.c b/src/expr.c index 3ce61b203..08d7277ec 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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) diff --git a/src/install.c b/src/install.c index bde69c994..8b02be965 100644 --- a/src/install.c +++ b/src/install.c @@ -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)); diff --git a/src/join.c b/src/join.c index dd0ce42bc..64156a22c 100644 --- a/src/join.c +++ b/src/join.c @@ -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) @@ -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)); } } diff --git a/src/md5sum.c b/src/md5sum.c index f75b6de02..de847ccb2 100644 --- a/src/md5sum.c +++ b/src/md5sum.c @@ -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 diff --git a/src/mknod.c b/src/mknod.c index 7f7cbc739..3f430af46 100644 --- a/src/mknod.c +++ b/src/mknod.c @@ -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)); @@ -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)); diff --git a/src/shuf.c b/src/shuf.c index 6a1aa0158..37a5a5554 100644 --- a/src/shuf.c +++ b/src/shuf.c @@ -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); diff --git a/src/sort.c b/src/sort.c index 360a1f140..b2336894f 100644 --- a/src/sort.c +++ b/src/sort.c @@ -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) diff --git a/src/uniq.c b/src/uniq.c index 9600ec094..836473624 100644 --- a/src/uniq.c +++ b/src/uniq.c @@ -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) |