[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