[tz] [PROPOSED] A couple more ptrdiff_t overflow safety checks
Paul Eggert
eggert at cs.ucla.edu
Wed Jan 4 22:19:04 UTC 2023
* 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
More information about the tz
mailing list