[cfe-dev] -ftrivial-auto-var-init=pattern vs =uninitialized and union initialization

Hubert Tong via cfe-dev cfe-dev at lists.llvm.org
Thu Sep 26 20:48:27 PDT 2019


On Thu, Sep 26, 2019 at 10:28 PM Vitaly Buka <vitalybuka at google.com> wrote:

> https://reviews.llvm.org/D68115
>
> On Tue, Sep 24, 2019 at 9:09 PM Hubert Tong <
> hubert.reinterpretcast at gmail.com> wrote:
>
>> On Mon, Sep 23, 2019 at 5:36 PM JF Bastien via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>
>>> Hi Vitaly,
>>>
>>> Indeed: there are cases where clang happened to honor the standard
>>> without intending to (through the magic of memcpy’ing globals), and
>>> auto-init=pattern broke this. I got a report about it a while ago and agree
>>> it’s an issue, I haven’t had time to fix it. It’s related to what C calls
>>> “designated initializers” to initialize structs. The relevant standardese
>>> from C17 are in 6.7.9 Initialization (the grammar has “designator” being
>>> either “ [ constant-expression ] ” or “ . identifier ”).
>>>
>>> The relevant rules are:
>>>
>>> “””
>>> Except where explicitly stated otherwise, for the purposes of this
>>> subclause unnamed members of objects of structure and union type do not
>>> participate in initialization. Unnamed members of structure objects have
>>> indeterminate value even after initialization.
>>>
>>> If an object that has automatic storage duration is not initialized
>>> explicitly, its value is indeterminate. If an object that has static or
>>> thread storage duration is not initialized explicitly, then:
>>> — if it has pointer type, it is initialized to a null pointer;
>>> — if it has arithmetic type, it is initialized to (positive or unsigned)
>>> zero;
>>> — if it is an aggregate, every member is initialized (recursively)
>>> according to these rules, and any padding is initialized to zero bits;
>>> — if it is a union, the first named member is initialized (recursively)
>>> according to these rules, and any padding is initialized to zero bits;
>>>
>>> The initialization shall occur in initializer list order, each
>>> initializer provided for a particular subobject overriding any previously
>>> listed initializer for the same subobject; all subobjects that are not
>>> initialized explicitly shall be initialized implicitly the same as objects
>>> that have static storage duration.
>>>
>>> If there are fewer initializers in a brace-enclosed list than there are
>>> elements or members of an aggregate, or fewer characters in a string
>>> literal used to initialize an array of known size than there are
>>> elements in the array, the remainder of the aggregate shall be initialized
>>> implicitly the same as objects that have static storage duration.
>>> “””
>>>
>> Unions are not aggregates in the C standard, so the last sentence does
>> not apply.
>>
>>
> I assume it's not going to hurt if we zero init there? I see a lot of code
> which assume that large fields will be initialized, and not sure how to use
> non-zero behaviour.
>
There are still platforms where such code breaks naturally anyway because
the zero value for a particular type is not the same as having zeroes for
all the bytes of its object representation. Under the status quo,
-ftrivial-auto-var-init has some ability to act as a tool for portability.
Although, as noted in this thread, the status quo is neither here nor there
with actually using the pattern (or using zeroes or something else).


>
>
>>
>>> I had fixed something in https://reviews.llvm.org/D61280 but it’s not
>>> sufficient.
>>>
>>>
>>> I don’t think fixing this is giving up: it’s doing what the standard
>>> mandates.
>>>
>>> Are you interested in fixing it?
>>>
>>>
>>>
>>> On Sep 23, 2019, at 2:20 PM, Vitaly Buka <vitalybuka at google.com> wrote:
>>>
>>> Hi everyone,
>>>
>>> I am trying to enable -ftrivial-auto-var-init=pattern on various code
>>> and noticed inconvenient inconsistency with code like [1].
>>>
>>> According standard, as I understand, only the first member of the union
>>> must be initialized and the tail of the second member can stay
>>> uninitialized. If we use -ftrivial-auto-var-init=pattern it fills the tail
>>> using our pattern. However by default GCC, clang (without
>>> -ftrivial-auto-var-init), msvc all initialize entire union with 0s. Not
>>> sure if it's just coincidence or guaranteed feature.
>>>
>>> So -ftrivial-auto-var-init=pattern breaks such code. Especially bad if
>>> you don't know that U is a union and ={} looks good there.
>>>
>>> Should we consider giving up here and using zeroes for union tails even
>>> with -ftrivial-auto-var-init=pattern?
>>>
>>> 1. Example:
>>> union U {
>>>   char small[2];
>>>   char large[100];
>>> };
>>> void f(void*);
>>> void test() {
>>>   union U u = {};
>>>   f(&u);
>>> }
>>>
>>>
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at lists.llvm.org
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20190926/5d15eba8/attachment.html>


More information about the cfe-dev mailing list