Subject: | check_max infinity loop on freebsd |
In function check_date_min for gmtime:
when after some iteration gmtime called with time = -67768038400720896,
it never returns to program.
Tested on freebsd-6.2 (amd64) and freebsd-7.0 (amd64).
Of cource, it's actually freebsd bug, but can we workaround this?
Can be showed with attached program (it is check_max.c with debugging
printf's ;-)
Subject: | check_max_d.c |
/* A little program to test the limits of your system's time functions */
#include <time.h>
#include <stdio.h>
#include <math.h>
time_t Time_Zero = 0;
/* Visual C++ 2008's difftime() can't do negative times */
double my_difftime(time_t left, time_t right) {
double diff = (double)left - (double)right;
return diff;
}
void check_date_max( struct tm * (*date_func)(const time_t *), char *func_name ) {
struct tm *date;
time_t time = 0;
time_t last_time = 0;
time_t time_change;
int i;
for (i = 0; i <= 63; i++) {
date = (*date_func)(&time);
/* date_func() broke or tm_year overflowed */
if(date == NULL || date->tm_year < 69)
break;
last_time = time;
time += time + 1;
/* time_t overflowed */
if( time < last_time )
break;
}
/* Binary search for the exact failure point */
time = last_time;
time_change = last_time / 2;
do {
time += time_change;
date = (*date_func)(&time);
/* date_func() broke or tm_year overflowed or time_t overflowed */
if(date == NULL || date->tm_year < 69 || time < last_time) {
time = last_time;
time_change = time_change / 2;
}
else {
last_time = time;
}
} while(time_change > 0);
printf("%s_max %.0f\n", func_name, my_difftime(last_time, Time_Zero));
}
void check_date_min( struct tm * (*date_func)(const time_t *), char *func_name ) {
struct tm *date;
time_t time = -1;
time_t last_time = 0;
time_t time_change;
int i;
for (i = 1; i <= 63; i++) {
date = (*date_func)(&time);
/* date_func() broke or tm_year underflowed */
if(date == NULL || date->tm_year > 70) {
printf("%d) break;\n",i);
break;
}
last_time = time;
time += time;
printf("%d) time: %ld\tlast: %ld\n",i,time,last_time);
/* time_t underflowed */
if( time > last_time ) {
printf("%d) time > last_time: %ld > %ld\n",i,time,last_time);
break;
}
}
/* Binary search for the exact failure point */
time = last_time;
time_change = last_time / 2;
printf("now time: %ld, time_change: %ld\n",time,time_change);
do {
time += time_change;
printf("enter date_func(%ld)\n",time);
date = (*date_func)(&time);
/* gmtime() broke or tm_year overflowed or time_t overflowed */
if(date == NULL || date->tm_year > 70 || time > last_time) {
time = last_time;
time_change = time_change / 2;
}
else {
last_time = time;
}
printf("time_change: %ld\n",time_change);
} while(time_change < 0);
printf("exit check_date_min\n");
printf("%s_min %.0f\n", func_name, my_difftime(last_time, Time_Zero));
}
int main(void) {
check_date_max(gmtime, "gmtime");
check_date_max(localtime, "localtime");
check_date_min(gmtime, "gmtime");
check_date_min(localtime, "localtime");
return 0;
}