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

Clive D.W. Feather clive at davros.org
Fri Nov 11 12:03:22 UTC 2022


Robert Elz via tz said:
>   | The 
>   | C committee has evidently gone to some length to require support for the 
>   | obscure and troublesome feature of copying uninitialized data, for 
>   | reasons that escape me.
> 
> I assume it is so portable code, which because of that cannot touch
> any implementation extension fields, has a way to copy a struct,
> based just upon its size (and a pointer to one of course), with the
> copy copying all fields (including non-standard extras) - because of
> that, copying field by field is out, and struct copy is out, because
> any uninit'd fields (probably extensions that the application doesn't
> know about either) might cause a trap.

As I said, I don't recall why we did it, but that's a good use case.

Struct copy is allowed to use (at least) memcpy or member-by-member
assignment, so it is allowed to trap on an uninitialized member.

> sizeof(struct whatever) always works to get the size, no matter how
> many extra fields might have been added, but also includes any padding
> that might exist, which is unlikely to be initialised unless the
> application has seen a need to memset() the whole thing.

Right. However, the contents of padding does not affect whether the
structure (or union) as a whole is a trap representation or not. In other
words, if all the members are initialized, you can safely copy the
structure without worrying about the padding.

Also note that all padding bytes become unspecified every time anything in
the structure changes; they're not required to stay constant.

(This is all C99 wording, of course.)

> So a means is needed to copy that uninitialised (potentially trapping)
> memory safely.

Yes, but see above.

> Kind of a pity they chose to make individual byte reads never trap
> (especially for architectures with no byte fetch from RAM instruction,
> where all fetches less than the word size need to be fetch/shift/mask
> type sequences) and so where if a word fetch generates a trap, the
> trap handler has to look at the code sequence that was going to be
> executed next, and hide the trap if just a byte was being accessed,
> but apparently, that's what would be required.

A byte is supposed to be individually addressable and accessible. So the
word fetch shouldn't be trapping.

On the XAP2, the minimum addressable and accessible object is 16 bits, so
at least on our implementation that was a byte (i.e. CHAR_BITS == 16). If
you wanted to get one or the other octet out of it, you had to do a
fetch/shift/mask.

-- 
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