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;
}

Reply via email to