Subject: bug#77840: [bug-diffutils] bug#77840: Testing diffutils 3.12 on PPC Mac OS X 10.4.11, Tiger, produces so many failures

From: Peter Dyballa <[email-masked]>
Date: Sat, 21 Jun 2025 16:22:34 +0200

> Am 20.06.2025 um 12:01 schrieb Peter Dyballa <[email-masked]>:
> 
> Comparing the function definition in both versions 3.12 and 3.10 I see that time is handled differently – cause found? In the end both functions simply have:
> 
>   set_color_context (RESET_CONTEXT);
>   putc ('\n', outfile);
> 
> The newer version has
> 
>     24      int nsec = ts.tv_nsec;
> 
> On Tiger /usr/include/time.h has:
> 
>     87 #ifndef _TIMESPEC                 88 #define _TIMESPEC
>     89 struct timespec {
>     90         time_t  tv_sec;         /* seconds */
>     91         long    tv_nsec;        /* and nanoseconds */
>     92 };
>     93 #endif
>     94
>     95 struct tm {
>     96         int     tm_sec;         /* seconds after the minute [0-60] */
>     97         int     tm_min;         /* minutes after the hour [0-59] */
>     98         int     tm_hour;        /* hours since midnight [0-23] */
>     99         int     tm_mday;        /* day of the month [1-31] */
>    100         int     tm_mon;         /* months since January [0-11] */
>    101         int     tm_year;        /* years since 1900 */
>    102         int     tm_wday;        /* days since Sunday [0-6] */
>    103         int     tm_yday;        /* days since January 1 [0-365] */
>    104         int     tm_isdst;       /* Daylight Savings Time flag */
>    105         long    tm_gmtoff;      /* offset from CUT in seconds */
>    106         char    *tm_zone;       /* timezone abbreviation */
>    107 };

In print_context_label()

   61		ts = get_stat_mtime (&inf->stat);

is executed. get_stat_mtime() is defined in lib/stat-time.h as:

  144	/* Return *ST's data modification time.  */
  145	_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
  146	get_stat_mtime (struct stat const *st)
  147	{
  148	#ifdef STAT_TIMESPEC
  149	  return STAT_TIMESPEC (st, st_mtim);
  150	#else
  151	  return (struct timespec) { .tv_sec = st->st_mtime,
  152	                             .tv_nsec = get_stat_mtime_ns (st) };
  153	#endif
  154	}

GDB goes to line #149, so STAT_TIMESPEC must be TRUE. ts reports that I have already spent 1¾·10⁹ seconds in front of my tv – plus zero nsec. Then in print_context_label()

   73	      struct tm const *tm = localtime (&ts.tv_sec);
   74	      int nsec = ts.tv_nsec;
 
is executed. If tm_mon = 0 stands for January, then tm holds the correct date (since 1900-01-01T00:00:00), nsec is zero. On nect line

   75	      if (tm && nstrftime (buf, sizeof buf, time_format, tm, localtz, nsec))

nstrftime() is called, which is #define'd in

	lib/nstrftime.c:18:#define my_strftime nstrftime

as:

 1057	/* Write information from TP into S according to the format
 1058	   string FORMAT, writing no more that MAXSIZE characters		==> shouldn't it be "than"?
 1059	   (including the terminating '\0') and returning number of
 1060	   characters written.  If S is NULL, nothing will be written
 1061	   anywhere, so to determine how many characters would be
 1062	   written, use NULL for S and (size_t) -1 for MAXSIZE.  */
 1063	size_t
 1064	my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
 1065	             const CHAR_T *format,
 1066	             const struct tm *tp extra_args_spec LOCALE_PARAM)
 1067	{
 1068	  bool tzset_called = false;
 1069	  return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
 1070	                              ZERO_PAD, -1,
 1071	                              &tzset_called extra_args LOCALE_ARG);
 1072	}

nstrftime is called with (s=0xbfffcb80 "\277\377\313\320", maxsize=52, format=0x5be2c "%Y-%m-%d %H:%M:%S.%N %z", tp=0xa000fd84, tz=0x0, ns=0). The value of localtz seems to be wrong, because it is never declared (tm contains tm_gmtoff = 7200 (2 hrs) and tm_zone = "CEST", both correct).

•••	And in the definition of my_strftime() it seems at least two COMMAs are missing:	•••

	    between "STRFTIME_ARG (size_t maxsize)" and "const CHAR_T *format",
	    between "const struct tm *tp" and "extra_args_spec LOCALE_PARAM",

and also a variable for nsec, separated by another COMMA? (lib/strftime.c has not changed from 3.11 to 3.12; 3.10 does not have this file, all is in lib/nstrftime.c while this file is in 3.11 and 3.12 almost empty.) diffutils 3.10 has the same function definition with missing COMMAs…

The call on line #1069 is:

	__strftime_internal (s=0xbfffcb80 "\277\377\313\320", maxsize=52, format=0x5be2c "%Y-%m-%d %H:%M:%S.%N %z", tp=0xa000fd84, upcase=false, yr_spec=ZERO_PAD, width=-1, tzset_called=0xbfffcb08, tz=0x0, ns=0) at strftime.c:1093

Near the end a breakpoint reveals that the form(at) has been filled in:

	__strftime_internal (s=0xbfffcb80 "2025-06-17 08:43:05.000000000 +0200", maxsize=52, format=0x5be2c "%Y-%m-%d %H:%M:%S.%N %z", tp=0xa000fd84, upcase=false, yr_spec=ZERO_PAD, width=-1, tzset_called=0xbfffcb08, tz=0x0, ns=0) at strftime.c:2240

and so __strftime_internal() finishes with:

	return i=35
	nstrftime (s=0xbfffcb80 "2025-06-17 08:43:05.000000000 +0200", maxsize=52, format=0x5be2c "%Y-%m-%d %H:%M:%S.%N %z", tp=0xa000fd84, tz=0x0, ns=0) at strftime.c:1072

So both

   99       print_context_label ("---", &inf[0], names[0], file_label[0]);
  100       print_context_label ("+++", &inf[1], names[1], file_label[1]);

succeed, with obviously no failure when accessing the files' time stamps.

--
Greetings

  Pete                           <]
             o        __o         |__    o       HPV, the real
    ___o    /I       -\<,         |o \  -\),-%     high speed!
___/\ /\___./ \___...O/ O____.....`-O-'-()--o_________________