scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 81300f52b0404d93e6123f8dc6de235c005b18e2
parent a5396a9b413649c049283e949c633d7db8877ee3
Author: Naveen Narayanan <zerous@simple-cc.org>
Date:   Tue, 29 Sep 2020 17:43:17 +0200

libc: Fix bug in mktime.c

norm() decrements tm_min(tm_hour, tm_mday, tm_year) if there is an
overshoot of tm_sec(tm_min,tm_hour,tm_mon) instead of respectively
incrementing tm_min(tm_hour, tm_mday, tm_year).
norm() increments tm_min(tm_hour, tm_mday, tm_year) if there is an
undershoot of tm_sec(tm_min,tm_hour,tm_mon) instead of respectively
decrementing tm_min(tm_hour, tm_mday, tm_year).

normalize() doesn't set the day of the month appropriately in the case
of day < 1 as it doesn't decrement mon prior to that. This happens
when there is an undershoot of tm_sec through tm_hour.

You can reproduce the bug by setting struct tm to the following and
calling mktime:

tim.tm_hour = -2;
tim.tm_mday = 1;
tim.tm_mon = 2;
tim.tm_year = 120;
tim.tm_isdst = 0;

t = mktime(&tim);
assert(t != -1);
assert(tim.tm_hour == 22);
assert(tim.tm_mday == 29);
assert(tim.tm_mon == 1);

Diffstat:
Msrc/libc/time/mktime.c | 6+++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c @@ -14,14 +14,14 @@ norm(int *val, int *next, int qty) v += d * qty; if (n > INT_MAX - d) return 0; - n += d; + n -= d; } if (v >= qty) { d = v / qty; v -= d * qty; if (n < INT_MIN + d) return 0; - n -= d; + n += d; } *val = v; @@ -48,7 +48,6 @@ normalize(struct tm *tm) _daysmon[FEB] = FEBDAYS(year); for (mon = tm->tm_mon; day < 1; --mon) { - day += _daysmon[mon]; if (mon == JAN) { if (year == EPOCH) return 0; @@ -56,6 +55,7 @@ normalize(struct tm *tm) _daysmon[FEB] = FEBDAYS(year); mon = DEC+1; } + day += _daysmon[mon-1]; } for (; day > _daysmon[mon]; ++mon) {