* private.h (TYPE_BIT): Now returns a signed value. * zdump.c (sumsize, xmalloc): Now takes signed args, like the result. (xstrsize): New function. (tzalloc, saveabbr): Use xstrsize to properly catch strings so long that their sizes do not fit into ptrdiff_t. Although quite implausible in real-life uses, it is possible according to the C standard. --- private.h | 2 +- zdump.c | 28 ++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/private.h b/private.h index 03ee4d10..b638e9e4 100644 --- a/private.h +++ b/private.h @@ -805,7 +805,7 @@ ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t); ** Finally, some convenience items. */ -#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT) +#define TYPE_BIT(type) (CHAR_BIT * (ptrdiff_t) sizeof(type)) #define TYPE_SIGNED(type) (((type) -1) < 0) #define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0) diff --git a/zdump.c b/zdump.c index 98537f4e..b93910ed 100644 --- a/zdump.c +++ b/zdump.c @@ -133,9 +133,9 @@ size_overflow(void) } /* Return A + B, exiting if the result would overflow either ptrdiff_t - or size_t. */ + or size_t. A and B are both nonnegative. */ ATTRIBUTE_REPRODUCIBLE static ptrdiff_t -sumsize(size_t a, size_t b) +sumsize(ptrdiff_t a, ptrdiff_t b) { #ifdef ckd_add ptrdiff_t sum; @@ -148,10 +148,22 @@ sumsize(size_t a, size_t b) size_overflow(); } +/* Return the size of of the string STR, including its trailing NUL. + Report an error and exit if this would exceed INDEX_MAX which means + pointer subtraction wouldn't work. */ +static ptrdiff_t +xstrsize(char const *str) +{ + size_t len = strlen(str); + if (len < INDEX_MAX) + return len + 1; + size_overflow(); +} + /* Return a pointer to a newly allocated buffer of size SIZE, exiting - on failure. SIZE should be nonzero. */ + on failure. SIZE should be positive. */ ATTRIBUTE_MALLOC static void * -xmalloc(size_t size) +xmalloc(ptrdiff_t size) { void *p = malloc(size); if (!p) { @@ -253,7 +265,7 @@ tzalloc(char const *val) static ptrdiff_t fakeenv0size; void *freeable = NULL; char **env = fakeenv, **initial_environ; - size_t valsize = strlen(val) + 1; + ptrdiff_t valsize = xstrsize(val); if (fakeenv0size < valsize) { char **e = environ, **to; ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ @@ -410,13 +422,13 @@ saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) if (HAVE_LOCALTIME_RZ) return ab; else { - size_t ablen = strlen(ab); - if (*bufalloc <= ablen) { + ptrdiff_t absize = xstrsize(ab); + if (*bufalloc < absize) { free(*buf); /* Make the new buffer at least twice as long as the old, to avoid O(N**2) behavior on repeated calls. */ - *bufalloc = sumsize(*bufalloc, ablen + 1); + *bufalloc = sumsize(*bufalloc, absize); *buf = xmalloc(*bufalloc); } -- 2.37.2