This is an archive of the discontinued LLVM Phabricator instance.

Variable auto-init: don't initialize aggregate padding of all aggregates
ClosedPublic

Authored by jfb on Apr 29 2019, 2:13 PM.

Details

Summary

C guarantees that brace-init with fewer initializers than members in the
aggregate will initialize the rest of the aggregate as-if it were static
initialization. In turn static initialization guarantees that padding is
initialized to zero bits.

rdar://problem/50188861

Diff Detail

Repository
rC Clang

Event Timeline

jfb created this revision.Apr 29 2019, 2:13 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2019, 2:13 PM

IIRC, C says *members* are initialized as if they were in static storage, which might mean that their interior padding should be zeroed, but I don't think says anything about the padding in the enclosing aggregate. But I think zero-initializing padding is probably the right thing to do in general under this flag.

erik.pilkington accepted this revision.Apr 30 2019, 1:35 PM
erik.pilkington added a subscriber: erik.pilkington.

LGTM, I think this makes sense.

This revision is now accepted and ready to land.Apr 30 2019, 1:35 PM
jfb added a comment.EditedApr 30 2019, 1:45 PM

IIRC, C says *members* are initialized as if they were in static storage, which might mean that their interior padding should be zeroed, but I don't think says anything about the padding in the enclosing aggregate. But I think zero-initializing padding is probably the right thing to do in general under this flag.

Quoth the Standard:

C17 6.7.9 Initialization ❡21
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.

C17 6.7.9 Initialization ❡10
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 and 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;

🙂

I don't think the implication is supposed to be that padding is zero-initialized or not depending on where in the aggregate it appears, but it doesn't really matter, I don't think we're arguing about the goal of this patch.

jfb added a comment.Apr 30 2019, 1:58 PM

I don't think the implication is supposed to be that padding is zero-initialized or not depending on where in the aggregate it appears, but it doesn't really matter, I don't think we're arguing about the goal of this patch.

The way I read it, C guarantees that an aggregate's padding is zero-initialized when you use brace-enclosed list *unless* you've mentioned all the elements / members of the aggregate. Fail to mention one → padding must be zero. Mention all of them → padding isn't guaranteed.

But then *reading* padding is another story. What triggered this change is C code that used memcmp on a struct with padding, and was expecting padding to be set. Not great code, but AFAICT technically correct.

jfb added a comment.Apr 30 2019, 3:53 PM

This seems uncontroversial, I'm happy to make follow-up change if you have suggestions.

This revision was automatically updated to reflect the committed changes.