Mark McIntyre said:
On Sat, 09 Oct 2004 01:35:49 +0200, in comp.lang.c , jacob navia
Come on, get a brain ! The code in the standard is not an implementation,
its a snippet showing the principle.
I'm afraid that it's a little more than that.
C99 7.23.3.1 says:
The asctime function converts the broken-down time in the
structure pointed to by timeptr into a string in the form
Sun Sep 16 01:03:52 1973\n\0
using the equivalent of the following algorithm.
char *asctime(const struct tm *timeptr)
{
static const char wday_name[7][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[12][3] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char result[26];
sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
wday_name[timeptr->tm_wday],
mon_name[timeptr->tm_mon],
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
1900 + timeptr->tm_year);
return result;
}
The implication is that a call to asctime() invokes undefined behavior
if the result doesn't fit into the 26-byte result buffer (e.g., if the
argument represents a date after the year 9999 or before -999).
It also invokes undefined behavior if timeptr is null or invalid, if
timeptr->tm_wday is outside the range 0..6, if timeptr->tm_mon is
outside the range 0..11, or if any of timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, or timeptr->tm_sec is outside the range -9..99
(or a larger range if the %d conversion for 1900+timeptr->tm_year
yields a string shorter than 4 characters).
The workaround for programmers is simple: don't do that.
What Jacob has advocated, if I recall correctly, is making the result
buffer larger, avoiding undefined behavior for a larger range of
years. (I don't think he's suggested fixing the other cases of
undefined behavior.) I actually agree with his suggestion; unlike the
other cases, the tm_year problem occurs with seemingly valid
arguments.
On the other hand, there's nothing preventing an implementation from
using a larger buffer. Since this would only affect programs that
currently invoke undefined behavior, it would be "the equivalent of
the following algorithm" as far as the standard is concerned.
On the other other hand, if the standard were changed to require a
larger buffer, it would be many years, if ever, before all
implementations conformed an programmers could depend on asctime()
working properly for years after 9999. (This argument applies to any
improvement of this kind; I don't consider it a strong argument.)
Some current implementations actually handle a year overflow by
writing a value that still fits into the result buffer, for example by
writing "****" for the year. Requiring a larger result buffer means
that a user program should invoke asctime() with a buffer larger than
26 characters to avoid undefined behavior. But this isn't really a
problem; it just moves the undefined behavior from the library to the
user's code.
Finally, the buffer overflow isn't asctime()'s only limitation. It's
probably not even its most serious one. It imposes a specific
English-language date format that's incompatible with ISO 8601, and
I've always found the trailing newline character annoying. These
problems *can't* be fixed without breaking existing code. If you want
anything beyond a quick-and-dirty timestamp display, most likely for
debugging, the strftime() function is more useful.
Jacob, I agree that it would be a good idea to fix this particular
buffer overflow. The committee doesn't, and I can see their point.
(Perhaps it would be better to make the behavior
implementation-defined.)
Suggesting that the committee explicitly endorses memory overwrites is
absurd.