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:
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) {