Paul Eggert <[email protected]> writes:

> and we can package this up into a function like this:
>
>   char c[CTIME_BUFSIZE];
>   safer_ctime (c, *tp);
>
> if people prefer simplicity.

Yes please.  Using complex APIs to implement safer_ctime is fine, but I
would prefer to not make existing ctime code more complicated when
fixing the undefined problem with (as)ctime(_r).

I would prefer having a global static variant since several uses of
ctime is in non-thread global application context where even the above
is unnecessarily complicated and wasteful of stack space.

A term "safe" is subjective (safer than what?  does it preclude even
safer variants?), how about using the 'c_' prefix?

So unless I'm missing something I envision these new functions:

       #define CTIME_BUFSIZE

       char *c_asctime(const struct tm *tm);
       char *c_asctime_r(const struct tm *tm, char *buf);

       char *c_ctime(const time_t *timep);
       char *c_ctime_r(const time_t *timep, char *buf);

that would never trigger undefined behaviour due to the year with 64-bit
time_t, and maybe fix some other underspecified aspect of the existing
functions.

CTIME_BUFSIZE should allow room for all possible years for 64-bit time_t
when time_t is 64-bit, and all possible years for 128-bit time_t when
time_t is 128-bit...  support for sizeof (time_t) > 8 may be unsupported
by gnulib though -- I'm not sure any reasonable system will ever use
128-bit time_t, although it is conceivable that some system may not have
efficient integers less than 128-bit and then sizeof (time_t) == 16
would make sense, I guess.  If that is even permitted.

64-bit time_t signed is sufficient for years -292471206707
.. 292471210647 or something like that.  So I suppose the longest
possible strings we could see with 64-bit time_t would be this:

"Sun Sep 16 01:03:52 -292471206707\n\0"

Even a 64-bit unsigned year would fit in the same string:

1970+2^64/60/60/24/365 =  584942419325
1970+2^63/60/60/24/365 =  292471210647
1970-2^64/60/60/24/365 = -584942415385
1970-2^63/60/60/24/365 = -292471206707

So CTIME_BUFSIZE should be 35?

It would be a nice property that all possible time_t values can be
converted into some human readable string that can be converted back to
same time_t value, for the same time zone.

I don't think anyone will care strongly what the string format is as
long as it follows the "Sun Sep 16 01:03:52 1973\n\0" format for all
valid 32-bit time_t values.  Cut-off years for comparison:

1970-2^32/60/60/24/365 = 1834
1970-2^31/60/60/24/365 = 1902
1970+2^31/60/60/24/365 = 2038
1970+2^32/60/60/24/365 = 2106

Thanks Bruno for fixing the primitives!  They are important to have as
tooling for any higher level functions.

Btw, how does 'difftime' handle 64-bit time_t?  I suppose it depends on
size of double.  It seems difftime cannot return errors, and doesn't
document undefined behaviour for input values:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/difftime.html

/Simon

Attachment: signature.asc
Description: PGP signature

Reply via email to