[tz] Minor (unimportant really) technical UB bug in strftime() ?

Clive D.W. Feather clive at davros.org
Tue Nov 8 14:28:56 UTC 2022


Robert Elz via tz said:
> The code for the %s strftime conversion starts as:
> (this taken from tzcode2022f strftime.c - but I suspect
> that many versions are the same)
> 
>                         case 's':
>                                 {
>                                         struct tm       tm;
>                                         char            buf[INT_STRLEN_MAXIMUM(
>                                                                 time_t) + 1];
>                                         time_t          mkt;  
>         
>                                         tm = *t;
>                                         mkt = mktime(&tm);
> 
> The "tm = *t;" line is the problem.   It (or more correctly, something
> to replace that) is needed, as *t is const, strftime() is not permitted
> to modify it, yet the struct tm * passed to mktime() is not const, as
> mktime is sometimes required to modify that struct before returning.
> 
> However, mktime() refers only to the fields tm_year tm_mon tm_mday
> tm_hour tm_min tm_sec and tm_isdst of the struct passed to it.  The
> %s conversion is defined as producing (in a decimal string format) the
> result of mktime() applied to the struct tm passed to strftime.
> Hence an application which intends to use strftime(..., "%s", ...)
> need only initialise those 7 fields, the other 2 (currently) standard
> fields (tm_yday and tm_wday) are explicitly ignored by mktime() on
> input, so there is no need to assign those values, and any other
> fields that might exist in a particular implementation are out of
> scope for a portable (conforming) application to touch, so cannot
> be initialised.
> 
> Since referring to an uninitialised variable is, I believe, technically
> undefined behaviour, doing a struct copy (copying all fields) can have
> that effect.

You could replace the assignment by a memcpy. Assignment via unsigned
chars (which is what memcpy does) are exempt from the undefined behaviour.

> On the other hand, hardware that balks at simply loading or copying,
> uninitialised values, without using them for any purpose is not exactly
> common (and half the world's code would probably break if an implementation
> that worked in such a manner was ever created) so I'd call this one of
> the less significant issues to worry about fixing.

It might not be common, but it was certainly something we had to consider.
It's why I wrote the wording about "trap representation"s in C99 the way I
did.

-- 
Clive D.W. Feather          | If you lie to the compiler,
Email: clive at davros.org     | it will get its revenge.
Web: http://www.davros.org  |   - Henry Spencer
Mobile: +44 7973 377646


More information about the tz mailing list