The attached test program (time_test.c) enters an infinite loop when run under macOS 10.6.
(compiled with: gcc -g3 time_test.c -o time_test.bin run with: ./time_test.bin) The localtime_r call has this backtrace: (gdb) bt #0 0x00007fff83860ad3 in timesub () from /usr/lib/libSystem.B.dylib #1 0x00007fff8386081c in _st_localsub () from /usr/lib/libSystem.B.dylib #2 0x00007fff83869d71 in localtime_r () from /usr/lib/libSystem.B.dylib #3 0x0000000100000f19 in main () at time_test.c:6 The gmtime_r call (commented) has this backtrace: (gdb) bt #0 0x00007fff83860b24 in timesub () from /usr/lib/libSystem.B.dylib #1 0x00007fff838929cc in gmtsub () from /usr/lib/libSystem.B.dylib #2 0x0000000100000f19 in main () at time_test.c:7 I think it's a bug in macOS' handling of large time values. (gdb) p /t large_time $3 = 1111111100001111001111010101010000000000000000000000000000000000 The same bug happens when gnulib calls gmtime_r or localtime_r (as in localtime_rz of time_rz.c). I originally reported the bug (it happened while building Emacs, which tracks gnulib) here: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27706 And it was also reported a second time here: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27736 I've written a makeshift program (attached; time_find.c) to show roughly which values of time_t cause the issue. It seems to be a range of values around time_t = -67768038400720896 (roughly year -2**31, I think.) The output is here: lib car313$ ./time_find.bin No hang for -67768038400770896 No hang for -67768038400760896 Hang detected for -67768038400750896 Hang detected for -67768038400740896 Hang detected for -67768038400730896 Hang detected for -67768038400720896 Hang detected for -67768038400710896 Hang detected for -67768038400700896 Hang detected for -67768038400690896 Hang detected for -67768038400680896 Hang detected for -67768038400670896 No hang for -67768038400660896 No hang for -67768038400650896 Could we put a workaround for these "bad" values of time_t in gnulib for this version of macOS? Thanks in advance.
#include "time.h" /* gnulib time.h */ int main() { time_t large_time = -67768038400720896; struct tm output_time; localtime_r(&large_time, &output_time); /* gmtime_r(&large_time, &output_time); */ return 0; }
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include "time.h" /* gnulib time.h */ #include <setjmp.h> #define TIME_CHECK_DELTA 10000 #define TIME_CHECK_RANGE 120000 static jmp_buf buf; static time_t orig_large_time = -67768038400770896; static time_t large_time = -67768038400770896; /* time_find.c */ int localtime_hang_handler () { printf ("Hang detected for %ld\n", (long) large_time); longjmp(buf, 1); } int main () { struct tm output_time; signal (SIGALRM, (void *) localtime_hang_handler); if(setjmp(buf)) next: large_time = large_time + TIME_CHECK_DELTA; alarm(1); localtime_r (&large_time, &output_time); printf ("No hang for %ld\n", (long) large_time); alarm(0); if (large_time < (orig_large_time + TIME_CHECK_RANGE)) { goto next; } return 0; }