From 790855e18a1dc027c0fb770de72a28081bc677fb Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 14 Oct 2003 20:08:25 +0000 Subject: [PATCH] Handle invalid suffixes and overflow independently, so that callers can treat them independently as needed. Fix some bugs in suffix handling. --- lib/ChangeLog | 31 ++++++++++++++++++++++++++ lib/human.c | 2 -- lib/xstrtoimax.c | 4 ++++ lib/xstrtol.c | 66 +++++++++++++++++++++++++++++++++++++------------------- lib/xstrtol.h | 14 ++++++++++-- lib/xstrtoul.c | 2 ++ lib/xstrtoumax.c | 4 ++++ 7 files changed, 97 insertions(+), 26 deletions(-) diff --git a/lib/ChangeLog b/lib/ChangeLog index c543f10a4..fd99ba93b 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,34 @@ +2003-10-14 Paul Eggert + + Handle invalid suffixes and overflow independently, so that + callers can treat them independently as needed. Fix some bugs in + suffix handling, e.g., "100k@" was not diagnosed as an invalid + suffix for a human-readable blocksize. The major caller-visible + change is the addition of a new + LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW enum value, indicating + that both overflow and suffix chars were found. + + * human.c (humblock): Don't check separately for invalid suffix + char; that is xstrtoumax's job (now that its bug is fixed). + * xstrtoimax.c (STRTOL_T_MINIMUM, STRTOL_T_MAXIMUM) [defined + INTMAX_MAX]: New macros. + * xstrtol.c (STRTOL_T_MINIMUM, STRTOL_T_MAXIMUM, TYPE_MINIMUM, + TYPE_MAXIMUM): New macros. + (bkm_scale, bkm_scale_by_power): Return strtol_error, not int. + (bkm_scale, bkm_scale_by_power, __xstrtol): Return maximal values + if overflow occurs, as it's what __strtol does and it's more useful + in practice. + (__xstrtol): If __strtol reports some error other than ERANGE, + reflect it to the caller as LONGINT_INVALID. If it reports + ERANGE, continue the rest of parsing, and report LONGINT_OVERFLOW + | LONGINT_INVALID_SUFFIX_CHAR if both errors occur. + * xstrtol.h (LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW): New enum + value. + (_STRTOL_ERROR): Handle it. Abort when given unknown error codes. + * xstrtoul.c (STRTOL_T_MINIMUM, STRTOL_T_MAXIMUM): New macros. + * xstrtoumax.c (STRTOL_T_MINIMUM, STRTOL_T_MAXIMUM) + [defined UINTMAX_MAX]: New macros. + 2003-10-14 Bruno Haible * fatal-signal.h: Improved comments. Suggested by Paul Eggert. diff --git a/lib/human.c b/lib/human.c index b342bf178..36cfd7348 100644 --- a/lib/human.c +++ b/lib/human.c @@ -450,8 +450,6 @@ humblock (char const *spec, uintmax_t *block_size, int *options) "eEgGkKmMpPtTyYzZ0"); if (e != LONGINT_OK) return e; - if (*ptr) - return LONGINT_INVALID_SUFFIX_CHAR; for (; ! ('0' <= *spec && *spec <= '9'); spec++) if (spec == ptr) { diff --git a/lib/xstrtoimax.c b/lib/xstrtoimax.c index 94c657786..2ba136772 100644 --- a/lib/xstrtoimax.c +++ b/lib/xstrtoimax.c @@ -30,4 +30,8 @@ #define __strtol strtoimax #define __strtol_t intmax_t #define __xstrtol xstrtoimax +#ifdef INTMAX_MAX +# define STRTOL_T_MINIMUM INTMAX_MIN +# define STRTOL_T_MAXIMUM INTMAX_MAX +#endif #include "xstrtol.c" diff --git a/lib/xstrtol.c b/lib/xstrtol.c index 4be09f169..32149397c 100644 --- a/lib/xstrtol.c +++ b/lib/xstrtol.c @@ -27,6 +27,8 @@ # define __strtol strtol # define __strtol_t long int # define __xstrtol xstrtol +# define STRTOL_T_MINIMUM LONG_MIN +# define STRTOL_T_MAXIMUM LONG_MAX #endif /* Some pre-ANSI implementations (e.g. SunOS 4) @@ -47,6 +49,15 @@ extern int errno; /* The extra casts work around common compiler bugs. */ #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \ + : (t) 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +#ifndef STRTOL_T_MINIMUM +# define STRTOL_T_MINIMUM TYPE_MINIMUM (__strtol_t) +# define STRTOL_T_MAXIMUM TYPE_MAXIMUM (__strtol_t) +#endif #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) # define IN_CTYPE_DOMAIN(c) 1 @@ -66,24 +77,30 @@ intmax_t strtoimax (); uintmax_t strtoumax (); #endif -static int +static strtol_error bkm_scale (__strtol_t *x, int scale_factor) { - __strtol_t product = *x * scale_factor; - if (*x != product / scale_factor) - return 1; - *x = product; - return 0; + if (TYPE_SIGNED (__strtol_t) && *x < STRTOL_T_MINIMUM / scale_factor) + { + *x = STRTOL_T_MINIMUM; + return LONGINT_OVERFLOW; + } + if (STRTOL_T_MAXIMUM / scale_factor < *x) + { + *x = STRTOL_T_MAXIMUM; + return LONGINT_OVERFLOW; + } + *x *= scale_factor; + return LONGINT_OK; } -static int +static strtol_error bkm_scale_by_power (__strtol_t *x, int base, int power) { + strtol_error err = LONGINT_OK; while (power--) - if (bkm_scale (x, base)) - return 1; - - return 0; + err |= bkm_scale (x, base); + return err; } /* FIXME: comment. */ @@ -95,6 +112,7 @@ __xstrtol (const char *s, char **ptr, int strtol_base, char *t_ptr; char **p; __strtol_t tmp; + strtol_error err = LONGINT_OK; assert (0 <= strtol_base && strtol_base <= 36); @@ -111,8 +129,6 @@ __xstrtol (const char *s, char **ptr, int strtol_base, errno = 0; tmp = __strtol (s, p, strtol_base); - if (errno != 0) - return LONGINT_OVERFLOW; if (*p == s) { @@ -123,6 +139,12 @@ __xstrtol (const char *s, char **ptr, int strtol_base, else return LONGINT_INVALID; } + else if (errno != 0) + { + if (errno != ERANGE) + return LONGINT_INVALID; + err = LONGINT_OVERFLOW; + } /* Let valid_suffixes == NULL mean `allow any suffix'. */ /* FIXME: update all callers except the ones that allow suffixes @@ -130,19 +152,19 @@ __xstrtol (const char *s, char **ptr, int strtol_base, if (!valid_suffixes) { *val = tmp; - return LONGINT_OK; + return err; } if (**p != '\0') { int base = 1024; int suffixes = 1; - int overflow; + strtol_error overflow; if (!strchr (valid_suffixes, **p)) { *val = tmp; - return LONGINT_INVALID_SUFFIX_CHAR; + return err | LONGINT_INVALID_SUFFIX_CHAR; } if (strchr (valid_suffixes, '0')) @@ -225,18 +247,18 @@ __xstrtol (const char *s, char **ptr, int strtol_base, default: *val = tmp; - return LONGINT_INVALID_SUFFIX_CHAR; + return err | LONGINT_INVALID_SUFFIX_CHAR; break; } - if (overflow) - return LONGINT_OVERFLOW; - - (*p) += suffixes; + err |= overflow; + *p += suffixes; + if (**p) + err |= LONGINT_INVALID_SUFFIX_CHAR; } *val = tmp; - return LONGINT_OK; + return err; } #ifdef TESTING_XSTRTO diff --git a/lib/xstrtol.h b/lib/xstrtol.h index 9af90aad3..f3b9295f3 100644 --- a/lib/xstrtol.h +++ b/lib/xstrtol.h @@ -32,7 +32,16 @@ # ifndef _STRTOL_ERROR enum strtol_error { - LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW + LONGINT_OK = 0, + + /* These two values can be ORed together, to indicate that both + errors occurred. */ + LONGINT_OVERFLOW = 1, + LONGINT_INVALID_SUFFIX_CHAR = 2, + + LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW = (LONGINT_INVALID_SUFFIX_CHAR + | LONGINT_OVERFLOW), + LONGINT_INVALID = 4 }; typedef enum strtol_error strtol_error; # endif @@ -49,7 +58,7 @@ _DECLARE_XSTRTOL (xstrtoumax, uintmax_t) { \ switch ((Err)) \ { \ - case LONGINT_OK: \ + default: \ abort (); \ \ case LONGINT_INVALID: \ @@ -58,6 +67,7 @@ _DECLARE_XSTRTOL (xstrtoumax, uintmax_t) break; \ \ case LONGINT_INVALID_SUFFIX_CHAR: \ + case LONGINT_INVALID_SUFFIX_CHAR | LONGINT_OVERFLOW: \ error ((Exit_code), 0, "invalid character following %s in `%s'", \ (Argument_type_string), (Str)); \ break; \ diff --git a/lib/xstrtoul.c b/lib/xstrtoul.c index 6140bbee2..285f7b96f 100644 --- a/lib/xstrtoul.c +++ b/lib/xstrtoul.c @@ -1,4 +1,6 @@ #define __strtol strtoul #define __strtol_t unsigned long int #define __xstrtol xstrtoul +#define STRTOL_T_MINIMUM 0 +#define STRTOL_T_MAXIMUM ULONG_MAX #include "xstrtol.c" diff --git a/lib/xstrtoumax.c b/lib/xstrtoumax.c index 59d6ecf5c..a8858bf6d 100644 --- a/lib/xstrtoumax.c +++ b/lib/xstrtoumax.c @@ -30,4 +30,8 @@ #define __strtol strtoumax #define __strtol_t uintmax_t #define __xstrtol xstrtoumax +#ifdef UINTMAX_MAX +# define STRTOL_T_MINIMUM 0 +# define STRTOL_T_MAXIMUM UINTMAX_MAX +#endif #include "xstrtol.c" -- 2.11.0