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