This is an archive of the discontinued LLVM Phabricator instance.

[randstruct] Move initializer check to be more effective
ClosedPublic

Authored by void on Apr 29 2022, 1:15 PM.

Details

Summary

If a randomized structure has an initializer with a dedicated
initializer in it, the field initialzed by that dedicated initializer
may end up at the end of the RecordDecl. This however may skip the
random layout initization check.

struct t {
   int a, b, c, d, e;
} x = { .a = 2, 4, 5, 6 };

Let's say that "a" is lands as the last field after randomization. The
call to CheckDesignatedInitializer sets the iterator to the end of the
initializer list. During the next iteration of the initializer list
check, it detects that and fails to issue the error about initializing
a randomized struct with non-designated initializer. Instead, it issues
an error about "excess elements in struct initializer", which is
confusing under these circumstances.

Diff Detail

Event Timeline

void created this revision.Apr 29 2022, 1:15 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 1:15 PM
Herald added a subscriber: StephenFan. · View Herald Transcript
void requested review of this revision.Apr 29 2022, 1:15 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 1:15 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
struct t {
   int a, b, c, d, e;
} x = { .a = 2, 4, 5, 6 };

This situation seems like it should be an error, shouldn't it? The user specified one designated initializer (yay, that one is correct), but the rest are positional initializers and so there's no telling what they actually initialize due to field randomization.

clang/test/Sema/init-randomized-struct.c
1

Why is this change needed?

(Also, shouldn't there be other test coverage added to the file?)

void added a comment.EditedMay 2 2022, 12:45 PM
struct t {
   int a, b, c, d, e;
} x = { .a = 2, 4, 5, 6 };

This situation seems like it should be an error, shouldn't it? The user specified one designated initializer (yay, that one is correct), but the rest are positional initializers and so there's no telling what they actually initialize due to field randomization.

That is diagnosed as an error. The issue is that after randomization, the a field is placed at the end of the structure. The initializer checker then sees the .a = 2 and says, "Ah! That's the one at the end of the structure. Any non-designated initializers afterwards will be excess ones," which is what happens. But that warning is completely mysterious to the end users who isn't told that they can't have a non-designated initializer on a randomized structure. Moving the diagnostic check allows the correct warning to be emitted instead of the "excess elements" one.

clang/test/Sema/init-randomized-struct.c
1

That seed is how to replicate this issue. The test exists and is triggered by this change. I can add a comment to that effect.

void added a comment.May 2 2022, 12:46 PM
struct t {
   int a, b, c, d, e;
} x = { .a = 2, 4, 5, 6 };

This situation seems like it should be an error, shouldn't it? The user specified one designated initializer (yay, that one is correct), but the rest are positional initializers and so there's no telling what they actually initialize due to field randomization.

That is diagnosed as an error. The issue is that after randomization, the a field is placed at the end of the structure. The initializer checker then sees the .a = 2 and says, "Ah! That's the one at the end of the structure. Any non-designated initializers afterwards will be excess ones," which is what happens. But that warning is completely mysterious to the end users who isn't told that they can't have a non-designated initializer on a randomized structure. Moving the diagnostic allows the correct warning to be emitted instead of the "excess elements" one.

s/is placed/may be places/

aaron.ballman accepted this revision.May 3 2022, 4:35 AM
struct t {
   int a, b, c, d, e;
} x = { .a = 2, 4, 5, 6 };

This situation seems like it should be an error, shouldn't it? The user specified one designated initializer (yay, that one is correct), but the rest are positional initializers and so there's no telling what they actually initialize due to field randomization.

That is diagnosed as an error. The issue is that after randomization, the a field is placed at the end of the structure. The initializer checker then sees the .a = 2 and says, "Ah! That's the one at the end of the structure. Any non-designated initializers afterwards will be excess ones," which is what happens. But that warning is completely mysterious to the end users who isn't told that they can't have a non-designated initializer on a randomized structure. Moving the diagnostic check allows the correct warning to be emitted instead of the "excess elements" one.

Ohhhhh! Thank you for the extra explanation, that makes a lot more sense to me now. LGTM with a commenting request.

clang/test/Sema/init-randomized-struct.c
1

Yeah, adding such a comment would be helpful, both for code archeology and as a hint to others editing the file in the future that this seed value is special and should not be changed.

This revision is now accepted and ready to land.May 3 2022, 4:35 AM
This revision was automatically updated to reflect the committed changes.