Browse Source

libc: fix off-by-one errors in localtime

K. Lange 11 months ago
parent
commit
84023ed829
2 changed files with 21 additions and 5 deletions
  1. 16 0
      apps/test-localtime.c
  2. 5 5
      libc/time/localtime.c

+ 16 - 0
apps/test-localtime.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <time.h>
+
+int main(int argc, char * argv[]) {
+	time_t i = 1576000000;
+	while (i < 2000000000) {
+		struct tm * t = localtime(&i);
+
+		if (t->tm_sec < 0 || t->tm_sec >= 60) fprintf(stderr, "Erroneous value at %ld: sec = %d\n", i, t->tm_sec);
+		if (t->tm_min < 0 || t->tm_min >= 60) fprintf(stderr, "Erroneous value at %ld: min = %d\n", i, t->tm_min);
+		if (t->tm_hour < 0 || t->tm_hour >= 24) fprintf(stderr, "Erroneous value at %ld (%s) hour = %d\n", i, asctime(t), t->tm_hour);
+
+		i++;
+	}
+	return 0;
+}

+ 5 - 5
libc/time/localtime.c

@@ -72,7 +72,7 @@ struct tm *localtime_r(const time_t *timep, struct tm * _timevalue) {
 		fprintf(stderr, "adding %d...\n", added);
 		long secs = added * 86400;
 
-		if (seconds + secs >= *timep + 1) {
+		if (seconds + secs > *timep) {
 			_timevalue->tm_year = year - 1900;
 			year_sec = seconds;
 			fprintf(stderr, "The year is %d, year_sec=%d\n", year, year_sec);
@@ -80,20 +80,20 @@ struct tm *localtime_r(const time_t *timep, struct tm * _timevalue) {
 				fprintf(stderr, "Checking %d\n", month);
 				secs = days_in_month(month, year) * SEC_DAY;
 				fprintf(stderr, "%d vs %d\n", seconds + secs, *timep);
-				if (seconds + secs >= *timep) {
+				if (seconds + secs > *timep) {
 					fprintf(stderr, "The month is %d.\n", month);
 					_timevalue->tm_mon = month - 1;
 					for (int day = 1; day <= days_in_month(month, year); ++day) {
 						secs = 60 * 60 * 24;
 						fprintf(stderr, "Checking day %d, %d vs . %d\n", day, seconds + secs, *timep);
-						if (seconds + secs >= *timep) {
+						if (seconds + secs > *timep) {
 							fprintf(stderr, "The day is %d.\n", day);
 							_timevalue->tm_mday = day;
 							for (int hour = 1; hour <= 24; ++hour) {
 								secs = 60 * 60;
-								if (seconds + secs >= *timep) {
+								if (seconds + secs > *timep) {
 									long remaining = *timep - seconds;
-									_timevalue->tm_hour = hour-1;
+									_timevalue->tm_hour = hour - 1;
 									_timevalue->tm_min = remaining / 60;
 									_timevalue->tm_sec = remaining % 60; // can be 60 on a leap second, ignore that
 									_timevalue->tm_wday = day_of_week(*timep); // oh shit