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
signature.asc
Description: PGP signature
