Avoid undefined behavior if a contrived TZif file specifies a leap
second correction equal to -2**31 on host where INT_FAST32_MIN ==
-2**31 + 1.  ISO C before C23 allows such hosts, though I know of
no practical examples.
* NEWS: Mention this.
* localtime.c (struct lsinfo.ls_corr, tzloadbody, timesub)
(increment_overflow_time, leapcorr): Use int_fast32_2s instead of
int_fast32_t when the value might equal -2**31.
---
 NEWS        |  4 ++--
 localtime.c | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index d2aade51..539e5968 100644
--- a/NEWS
+++ b/NEWS
@@ -31,8 +31,8 @@ Unreleased, experimental changes
     (Undefined behavior reported by GitHub user Naveed8951.)
 
     Some other undefined behavior, triggered by TZif files containing
-    outlandish but conforming UT offsets, has also been fixed.
-    (Also reported by Naveed8951.)
+    outlandish but conforming UT offsets or leap second corrections,
+    has also been fixed.  (Also reported by Naveed8951.)
 
     zic no longer generates a no-op transition when
     simultaneous Rule and Zone changes cancel each other out.
diff --git a/localtime.c b/localtime.c
index 9b7bbaa9..16eec790 100644
--- a/localtime.c
+++ b/localtime.c
@@ -480,7 +480,7 @@ struct ttinfo {                             /* time type 
information */
 
 struct lsinfo {                                /* leap second information */
        time_t          ls_trans;       /* transition time */
-       int_fast32_t    ls_corr;        /* correction to apply */
+       int_fast32_2s   ls_corr;        /* correction to apply */
 };
 
 /* This abbreviation means local time is unspecified.  */
@@ -529,8 +529,8 @@ struct rule {
 static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
                         struct tm *);
 static bool increment_overflow(int *, int);
-static bool increment_overflow_time(time_t *, int_fast32_t);
-static int_fast32_t leapcorr(struct state const *, time_t);
+static bool increment_overflow_time(time_t *, int_fast32_2s);
+static int_fast32_2s leapcorr(struct state const *, time_t);
 static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
                          struct tm *);
 static bool tzparse(char const *, struct state *, struct state const *);
@@ -1006,7 +1006,7 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
            bool skip_datablock = stored == 4 && version;
            int_fast32_t datablock_size;
            int_fast64_t prevtr = -1;
-           int_fast32_t prevcorr;
+           int_fast32_2s prevcorr;
            int_fast32_2s
              ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt),
              ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt),
@@ -1112,7 +1112,7 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
                leapcnt = 0;
                for (i = 0; i < sp->leapcnt; ++i) {
                  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
-                 int_fast32_t corr = detzcode(p + stored);
+                 int_fast32_2s corr = detzcode(p + stored);
                  p += stored + 4;
 
                  /* Leap seconds cannot occur before the Epoch,
@@ -2277,7 +2277,7 @@ timesub(const time_t *timep, int_fast32_t offset,
        register const struct lsinfo *  lp;
        register time_t                 tdays;
        register const int *            ip;
-       register int_fast32_t           corr;
+       int_fast32_2s corr;
        register int                    i;
        int_fast32_t idays, rem, dayoff, dayrem;
        time_t y;
@@ -2467,7 +2467,7 @@ increment_overflow_time_64(time_t *tp, int_fast64_t j)
 }
 
 static bool
-increment_overflow_time(time_t *tp, int_fast32_t j)
+increment_overflow_time(time_t *tp, int_fast32_2s j)
 {
 #ifdef ckd_add
        return ckd_add(tp, *tp, j);
@@ -2945,7 +2945,7 @@ timegm(struct tm *tmp)
 }
 #endif
 
-static int_fast32_t
+static int_fast32_2s
 leapcorr(struct state const *sp, time_t t)
 {
        register struct lsinfo const *  lp;
-- 
2.51.0

Reply via email to