ref: 1c8ba5d798e7676ca4240e73db7fc36cbcfecdbb
parent: fe02e90431559e9440f10983457eb01eece016c0
author: Naveen Narayanan <zerous@simple-cc.org>
date: Tue Sep 29 13:43:17 EDT 2020
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);
--- a/src/libc/time/mktime.c
+++ b/src/libc/time/mktime.c
@@ -14,7 +14,7 @@
v += d * qty;
if (n > INT_MAX - d)
return 0;
- n += d;
+ n -= d;
}
if (v >= qty) {
d = v / qty;
@@ -21,7 +21,7 @@
v -= d * qty;
if (n < INT_MIN + d)
return 0;
- n -= d;
+ n += d;
}
*val = v;
@@ -48,7 +48,6 @@
_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 @@
_daysmon[FEB] = FEBDAYS(year);
mon = DEC+1;
}
+ day += _daysmon[mon-1];
}
for (; day > _daysmon[mon]; ++mon) {