This is an archive of the discontinued LLVM Phabricator instance.

[randstruct] Add randomize structure layout support
ClosedPublic

Authored by void on Mar 13 2022, 1:41 PM.

Details

Summary

The Randstruct feature is a compile-time hardening technique that
randomizes the field layout for designated structures of a code base.
Admittedly, this is mostly useful for closed-source releases of code,
since the randomization seed would need to be available for public and
open source applications.

Why implement it? This patch set enhances Clang’s feature parity with
that of GCC which already has the Randstruct feature. It's used by the
Linux kernel in certain structures to help thwart attacks that depend on
structure layouts in memory.

This patch set is a from-scratch reimplementation of the Randstruct
feature that was originally ported to GCC. The patches for the GCC
implementation can be found here:

https://www.openwall.com/lists/kernel-hardening/2017/04/06/14

Link: https://lists.llvm.org/pipermail/cfe-dev/2019-March/061607.html
Co-authored-by: Cole Nixon <nixontcole@gmail.com>
Co-authored-by: Connor Kuehl <cipkuehl@gmail.com>
Co-authored-by: James Foster <jafosterja@gmail.com>
Co-authored-by: Jeff Takahashi <jeffrey.takahashi@gmail.com>
Co-authored-by: Jordan Cantrell <jordan.cantrell@mail.com>
Co-authored-by: Nikk Forbus <nicholas.forbus@gmail.com>
Co-authored-by: Tim Pugh <nwtpugh@gmail.com>
Co-authored-by: Bill Wendling <isanbard@gmail.com>
Signed-off-by: Bill Wendling <isanbard@gmail.com>

Diff Detail

Event Timeline

void created this revision.Mar 13 2022, 1:41 PM
Herald added a project: Restricted Project. · View Herald Transcript
void requested review of this revision.Mar 13 2022, 1:41 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 13 2022, 1:41 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
void added subscribers: connorkuehl, Dan, xbolva00 and 10 others.

This is a soft reworking of @connorkuehl's work in https://reviews.llvm.org/D59254. Please take a look!

Thank you for working on this new security feature! I like it and I think it's heading in the right direction.

Can you please add a release note for the new functionality?

This is missing tests for the Driver diagnostics, the Sema diagnostics (including existing diagnostics like writing the attribute on the wrong subject or giving it args when it doesn't expect them, wrong language mode, etc), and the CodeGen behavior, so those should be added. Also, the Windows pre-commit CI is failing:

Failed Tests (7):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.AnonymousStructsAndUnionsRetainFieldOrder
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckAdjacentBitfieldsRemainAdjacentAfterRandomization
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckVariableLengthArrayMemberRemainsAtEndOfStructure
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MultipleAttrsRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.RandstructDoesNotOverrideThePackedAttr
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.ZeroWidthBitfieldsSeparateAllocationUnits
 
Testing Time: 676.49s
  Skipped          :     4
  Unsupported      :   202
  Passed           : 29832
  Expectedly Failed:    31
  Failed           :     7
clang/include/clang/AST/Decl.h
2842

It's unfortunate that every field node in the AST is now going to be 4 bytes larger for this feature; I worry about the extra memory pressure from the additional overhead, so if there's a way for us to save some space here, I think it might be worth it. (I'm worried that our max template instantiation depth will shrink because of this.)

4056

A setter that is marked const does not spark joy for me... Can we use friendship rather than mutability to solve this?

clang/include/clang/AST/Randstruct.h
35

Doing this with a global variable is unfortunate; it could make things harder when we multithread the frontend. Can we solve this without a global? (And if not, does this global need to be a ManagedStatic?)

clang/include/clang/Basic/Attr.td
3954–3955

Microsoft does not implement this __declspec, correct? If they don't, we shouldn't either (even if GCC does) unless there's a *very* good reason to do so. That's Microsoft's design space we're encroaching on.

I'd also like to understand the justification for adding a new keyword for this.

3964–3965

Same here.

clang/include/clang/Basic/AttrDocs.td
6389

I think it would help to explain the effects of this attribute in conjunction with structure packing techniques (the packed attribute and bit-fields) and whether any attempt is made to keep the structure packed or those fields together or not. I'd expect no such attempt is made, but people may want to know "attempts to pack this structure" and "randomize this structure layout" are not compatible. (We may want to diagnose in the case of seeing the packed attribute, in fact.)

We should also be more clear that the seed specified does not have to be numeric in nature (from the file or when directly on the command line).

clang/lib/AST/DeclBase.cpp
28 ↗(On Diff #414951)

Is this include necessary?

clang/lib/AST/Randstruct.cpp
73

This size seems as defensible as most others; do you plan to do more here, or should this comment be removed?

100

Oh cool, we do bit-field runs!

How should we handle anonymous bit-fields (if anything special should be done for them at all)? People usually use them for padding between bit-fields, so it's not clear to me how to treat them when randomizing.

180

This one seems a bit large to me; any reason not to use 16 again?

186
clang/lib/Parse/ParseDeclCXX.cpp
2063–2069 ↗(On Diff #414951)

I think this works okay for C, but I think if we ever attempted to provide this functionality in C++, the calls to addDecl() would be rather expensive because it eventually calls addedMember() which calculates information about the structure (whether it's copy constructible, has a trivial destructor, etc) and we don't need to redo any of that work.

However, for now, I think this is fine.

clang/lib/Sema/AnalysisBasedWarnings.cpp
2166–2167 ↗(On Diff #414951)
2503 ↗(On Diff #414951)

No, this function is only called when popping a function scope, and so the only declaration it has access to is the FunctionDecl. Or do I misunderstand the question?

clang/lib/Sema/SemaDecl.cpp
27

Is this include necessary?

clang/lib/Sema/SemaDeclAttr.cpp
8653–8659

I don't think this is sufficient. Consider redeclaration merging cases:

struct [[gnu::randomize_layout]] S;
struct [[gnu::no_randomize_layout]] S {};

struct [[gnu::no_randomize_layout]] T;
struct [[gnu::randomize_layout]] T {};

I think if the user accidentally does something like this, it should be diagnosed. I would have assumed this would warrant an error diagnostic because the user is obviously confused as to what they want, but it seems GCC ignores the subsequent diagnostic with a warning: https://godbolt.org/z/1q8dazYPW.

There's also the "confused attribute list" case which GCC just... does... things... with: https://godbolt.org/z/rnfsn7hG1. I think we want to behave more consistently with how we treat these cases.

Either way, we shouldn't be silent.

void marked 7 inline comments as done.Mar 17 2022, 4:13 PM
void added inline comments.
clang/include/clang/AST/Decl.h
4056

It was done to prevent a const_cast. It looks like the other setters are non-const. I'll see if I can get around that.

clang/include/clang/AST/Randstruct.h
35

Maybe this could be moved to LangOpts?

clang/include/clang/Basic/Attr.td
3954–3955

Good point. I'll remove those.

clang/lib/AST/DeclBase.cpp
28 ↗(On Diff #414951)

Hmm...that must have been from a previous change. Removed.

clang/lib/AST/Randstruct.cpp
73

It's probably not worth looking into unless it becomes an issue. I'll remove it.

100

Good question! I'm not sure either. On one hand, I'm rather concerned about changing bitfield order in general, but it appears to be something that GCC's plugin does, so...

180

The code above looks to apply mostly to bitfield runs. This is for all fields in a structure. I assumed (without proof) that this will always be larger than the bitfield runs. :-)

clang/lib/Parse/ParseDeclCXX.cpp
2063–2069 ↗(On Diff #414951)

God help the person who does this for C++! :-)

Joking aside, supporting C++ will probably result in a almost total rewrite of this feature.

clang/lib/Sema/AnalysisBasedWarnings.cpp
2503 ↗(On Diff #414951)

Sounds good to me. Is this the best place for this check then?

clang/lib/Sema/SemaDeclAttr.cpp
8653–8659

The GCC feature is done via a plugin in Linux. So godbolt probably won't work in this case. I'll check to see how GCC responds to these attribute situations.

void updated this revision to Diff 416354.Mar 17 2022, 4:13 PM
void marked 3 inline comments as done.

General cleanup of code. Removing unneeded headers and comments. Removing a "const" from a setter. Not defining this for MS's declspecs or making the attributes keywords.

aaron.ballman added inline comments.Mar 18 2022, 5:52 AM
clang/include/clang/AST/Randstruct.h
35

That's a really good idea, let's go with that approach.

clang/include/clang/Basic/DiagnosticSemaKinds.td
11580
clang/lib/AST/Randstruct.cpp
100

Yeah, I was really surprised about bit-fields as well. I'm especially concerned that bit-fields which were [un]carefully straddling allocation unit boundaries might be rearranged such that subtle atomic bugs and whatnot will be exposed.

If we find these sort of concerns are valid in real world code, we may want to add a second command line option (off-by-default, perhaps) for enabling rearranging bit-fields. But for now, I think it's fine to follow GCC's lead here.

180

I think that's a safe assumption and it's probably not worth worrying about overly much. It's more that 16 bit-fields seemed like it would be large enough to cover most bit-fields in a class while still being "small", but 64 fields seems likely to be way larger than most structures will need and isn't very small.

That said, I don't have a strong feeling here and I think the numbers are defensible unless we measure something that says otherwise.

clang/lib/Sema/AnalysisBasedWarnings.cpp
2503 ↗(On Diff #414951)

I'm not convinced it is the best place for it -- analysis-based warnings are typically ones that require a CFG to be analyzed and so they are only run once we know the function body itself is valid (they also typically require the user to manually enable the checks -- your check runs always, even if the user hasn't enabled struct randomization, so it walks a lot of ASTs it doesn't need to). Your check doesn't require a CFG at all and it seems like it can be done purely when building the AST. I think a better place for this checking is in SemaCast.cpp in the CastOperation class.

void updated this revision to Diff 416808.Mar 20 2022, 5:07 PM

Move SEED into LangOpts.

void updated this revision to Diff 418305.Mar 25 2022, 1:00 PM

Fix how the command line flags are handled.

void updated this revision to Diff 418307.Mar 25 2022, 1:05 PM
void marked 5 inline comments as done.

Add "err_" prefix to error message.

clang/include/clang/AST/Decl.h
2842

Turns out this field wasn't used. I removed it.

clang/include/clang/Basic/AttrDocs.td
6389

Having randomization and the packed attribute probably isn't the best option. I'll modify things to prevent that from happening.

void updated this revision to Diff 418356.Mar 25 2022, 4:19 PM
void marked 2 inline comments as done.

Move casting check into the SemaCast where it belongs.

void marked 2 inline comments as done.Mar 25 2022, 4:19 PM
void updated this revision to Diff 418480.Mar 27 2022, 7:14 PM
  • Make sure the command line seed is properly passed on to each front-end level.
  • Some general cleanups.
void updated this revision to Diff 419282.Mar 30 2022, 3:57 PM

Moved the randomization to a better spot.

void added a comment.Mar 30 2022, 11:23 PM

Friendly ping for review. :-)

Generally I think things are looking pretty good, but there's still an open question and Precommit CI is still failing on Windows:

Failed Tests (7):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.AnonymousStructsAndUnionsRetainFieldOrder
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckAdjacentBitfieldsRemainAdjacentAfterRandomization
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckVariableLengthArrayMemberRemainsAtEndOfStructure
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MultipleAttrsRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.RandstructDoesNotOverrideThePackedAttr
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.ZeroWidthBitfieldsSeparateAllocationUnits
clang/include/clang/Basic/Attr.td
3961–3975

This gets rid of one of the AST nodes and uses an accessor instead. e.g., the user can still write [[gnu::no_randomize_layout]] on a struct declaration, we'll generate a RandomizeLayoutAttr for it, and you can call ->isDisabled() on an object to tell whether it's the no_ spelling or not.

I don't feel super strong about this change, so if it turns out to make code elsewhere significantly worse, feel free to ignore. My reasoning for combing is that the no variant doesn't carry much semantic weight but eats up an attribute kind value just the same; it seemed like a heavy use for an AST node.

clang/lib/Sema/SemaDeclAttr.cpp
8653–8659

Thoughts on this?

void added a comment.Apr 4 2022, 12:10 PM

Generally I think things are looking pretty good, but there's still an open question and Precommit CI is still failing on Windows:

Failed Tests (7):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.AnonymousStructsAndUnionsRetainFieldOrder
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckAdjacentBitfieldsRemainAdjacentAfterRandomization
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckVariableLengthArrayMemberRemainsAtEndOfStructure
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MultipleAttrsRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.RandstructDoesNotOverrideThePackedAttr
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.ZeroWidthBitfieldsSeparateAllocationUnits

Strange. I wonder if Windows is using a different algorithm for the randomization function. I'll investigate and see what can be done here.

void updated this revision to Diff 420294.Apr 4 2022, 1:32 PM
void marked an inline comment as done.

Simplify the attributes by using an accessor instead of a separate "no_ranomize_layout" attribute.

Release note is missing

void added a comment.Apr 4 2022, 1:40 PM

Generally I think things are looking pretty good, but there's still an open question and Precommit CI is still failing on Windows:

Failed Tests (7):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.AnonymousStructsAndUnionsRetainFieldOrder
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckAdjacentBitfieldsRemainAdjacentAfterRandomization
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckVariableLengthArrayMemberRemainsAtEndOfStructure
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MultipleAttrsRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.RandstructDoesNotOverrideThePackedAttr
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.ZeroWidthBitfieldsSeparateAllocationUnits

Do you have a URL for this failure or the output message?

void added a comment.Apr 4 2022, 1:49 PM

Release note is missing

Sorry about that. I'll add one with the next update.

Generally I think things are looking pretty good, but there's still an open question and Precommit CI is still failing on Windows:

Failed Tests (7):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.AnonymousStructsAndUnionsRetainFieldOrder
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckAdjacentBitfieldsRemainAdjacentAfterRandomization
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.CheckVariableLengthArrayMemberRemainsAtEndOfStructure
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MultipleAttrsRandomize
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.RandstructDoesNotOverrideThePackedAttr
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.ZeroWidthBitfieldsSeparateAllocationUnits

Do you have a URL for this failure or the output message?

https://reviews.llvm.org/D121556
->
Harbormaster completed remote builds in B156477: Diff 418480. (https://reviews.llvm.org/harbormaster/build/233718/)
->
x64 windows failed (https://buildkite.com/llvm-project/premerge-checks/builds/86170#c5c61c34-004b-4e62-a3b4-4654fb8d1dc7)

void updated this revision to Diff 420307.Apr 4 2022, 2:17 PM
  • Add an entry in the Release Notes.
  • Change the command line flags to better match the attribute naming.
void updated this revision to Diff 420312.Apr 4 2022, 2:34 PM

First pass at fixing the Windows unit test errors.

void updated this revision to Diff 420332.Apr 4 2022, 3:29 PM

Second attempt to fix Windows errors. Expecting one more iteration.

void added inline comments.Apr 5 2022, 12:35 PM
clang/lib/Sema/SemaDeclAttr.cpp
8653–8659

Okay, finally tested it with the GCC plugin. It doesn't produce a diagnostic. I'm not sure if that's the correct behavior, but at least it matches. How is such a thing handled with similar attributes?

aaron.ballman added inline comments.Apr 6 2022, 11:27 AM
clang/include/clang/AST/Randstruct.h
32–36

Might as well be consistent with the other type names.

clang/include/clang/Driver/Options.td
2125–2136

You should condense these a bit to keep the style the same as the surrounding code.

clang/lib/AST/Randstruct.cpp
72–76

Default ctor already does the right thing, so no need to do the initialization.

clang/lib/Sema/SemaDeclAttr.cpp
8653–8659

Okay, finally tested it with the GCC plugin. It doesn't produce a diagnostic. I'm not sure if that's the correct behavior, but at least it matches. How is such a thing handled with similar attributes?

As you might be unsurprised to learn: inconsistently. :-D However, we typically try to make attributes mutually exclusive (e.g., hot and cold, global and device, etc).

Unfortunately, I gave you some advice earlier to combine into one semantic attribute and that may have been less-than-awesome advice. Attr.td supports the ability to trivially define to attributes as mutually exclusive (e.g., def : MutualExclusions<[Hot, Cold]>; but this works on the *attribute* level and not the *spelling* level.

It's probably easier for you to split the definition back into two attributes in Attr.td and just use the MutualExclusions support we already have. Sorry for that churn! If you wanted to (and I certainly don't insist), another option would be to modify ClangAttrEmitter.cpp and Attr.td to support mutual exclusion syntax on the spelling level, so you could do something like:

def : MutualExclusions<[
  RandomizeLayout<GCC<"randomize_layout">>,
  RandomizeLayout<GCC<"no_randomize_layout">>
]>;

where you specify the attribute and the spelling, then you could leave RandomizeLayout as a single semantic spelling. But again, I don't insist.

clang/unittests/AST/RandstructTest.cpp
155–159

Any idea what's gone wrong here? (Do we have a bug to file because these come out reversed? If so, can you add a FIXME comment here that we expect this test to change someday?)

209–214

Is the assertion unrelated to the changes in your patch and you just happen to hit it with this test? (I get worried when tests trigger assertions.)

void updated this revision to Diff 420972.Apr 6 2022, 12:32 PM
void marked 3 inline comments as done.

Don't re-randomize a structure. Also some minor style changes.

clang/lib/Sema/SemaDecl.cpp
27

Yes. There's a call to randstruct::randomizeStructureLayout below.

clang/unittests/AST/RandstructTest.cpp
155–159

I think it's just a case where Windows' algorithm for std::mt19937 is subtly different than the one for Linux. I'm not sure we should worry about it too much, to be honest. As long as it produces a deterministic output on the same platform we should be fine. I think it's expected that the same compiler/environment is used during all compilation steps. (I.e., one's not going to compile a module on Windows for a kernel build on Linux.)

209–214

To be honest, I haven't looked at these tests. I inherited them from the previous code base. I'll revisit these and probably delete them if they're not useful.

Recap: aside from the function merging behavior and the possible question about assertions in tests, I think this is ready to go.

clang/lib/Sema/SemaDecl.cpp
27

Oh derp, I missed that. :-)

clang/unittests/AST/RandstructTest.cpp
155–159

Okay, that's a great reason for this to be left alone.

209–214

Okay, that sounds good to me.

void updated this revision to Diff 421358.Apr 7 2022, 3:57 PM

Make the randomize_layout and no_randomize_layout attributes mutually exclutsive.

void updated this revision to Diff 421416.Apr 7 2022, 9:59 PM

Fix bad formatting.

aaron.ballman accepted this revision.Apr 8 2022, 4:22 AM

Precommit CI is failing on one test:

Failed Tests (1):

Clang :: Misc/pragma-attribute-supported-attributes-list.test

but with that test fixed, this LGTM! (Feel free to land with the test fixed unless you want another round of review.) Thank you for the awesome new security feature!

This revision is now accepted and ready to land.Apr 8 2022, 4:22 AM
void updated this revision to Diff 421616.Apr 8 2022, 12:41 PM

Fix simple test.

void added a comment.Apr 8 2022, 12:42 PM

Precommit CI is failing on one test:

Failed Tests (1):

Clang :: Misc/pragma-attribute-supported-attributes-list.test

but with that test fixed, this LGTM! (Feel free to land with the test fixed unless you want another round of review.) Thank you for the awesome new security feature!

That'll teach me not to run tests. :-)

Thanks, Aaron!

This revision was landed with ongoing or failed builds.Apr 8 2022, 12:48 PM
This revision was automatically updated to reflect the committed changes.
dyung added a subscriber: dyung.Apr 8 2022, 1:56 PM

Hi, the test you added is failing on the PS4 Windows bot https://lab.llvm.org/buildbot/#/builders/216/builds/2647.

Can you take a look?

void added a comment.Apr 8 2022, 2:07 PM

Hi, the test you added is failing on the PS4 Windows bot https://lab.llvm.org/buildbot/#/builders/216/builds/2647.

Can you take a look?

Crud! I thought I got all of the Windows issues. I'll fix soon. Sorry about that!

thakis added a subscriber: thakis.Apr 8 2022, 4:54 PM

Looks like this breaks tests on mac: http://45.33.8.238/macm1/32938/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

void added a comment.Apr 8 2022, 5:05 PM

Looks like this breaks tests on mac: http://45.33.8.238/macm1/32938/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

Ugh! This sucks. I just removed the test until I can get it to work on all platforms.

thakis added a comment.Apr 8 2022, 5:13 PM

It's more important to remove it from the cmakelists file than to delete the source file ;)

Please revert the whole thing instead of just removing the test coverage though. You can reland when the test is figured out, and that makes sure this doesn't stay in without coverage.

void added a comment.Apr 8 2022, 5:44 PM

It's more important to remove it from the cmakelists file than to delete the source file ;)

Please revert the whole thing instead of just removing the test coverage though. You can reland when the test is figured out, and that makes sure this doesn't stay in without coverage.

I'd rather not re-land the whole thing. The test isn't that important, and quite frankly it might not be possible to test it with the unittest. Too many architectures seem to have a different randomization algorithm.

thakis added a comment.Apr 8 2022, 5:52 PM

Why? This is a fairly small CL. It should be easy to reland, and there shouldn't be any rebasing pain.

You should at least check with your reviewers that they're fine relanding this without test.

You can use llvm::shuffle to avoid STL impl difference

clang/lib/AST/Randstruct.cpp
161

llvm::shuffle to avoid

Windows test is still failing after the std::shuffle => llvm::shuffle change, guess time for revert.

../../clang/unittests/AST/RandstructTest.cpp(165): error: Expected equality of these values:
  Expected
    Which is: { "lettuce", "bacon", "mayonnaise", "tomato" }
  getFieldNamesFromRecord(RD)
    Which is: { "bacon", "lettuce", "mayonnaise", "tomato" }
[  FAILED  ] StructureLayoutRandomization.MarkedRandomize (47 ms)
[----------] 1 test from StructureLayoutRandomization (47 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (47 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] StructureLayoutRandomization.MarkedRandomize

 1 FAILED TEST

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. 
********************
Failed Tests (1):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize
MaskRay reopened this revision.Apr 8 2022, 6:37 PM
This revision is now accepted and ready to land.Apr 8 2022, 6:37 PM
MaskRay requested changes to this revision.Apr 8 2022, 6:37 PM
This revision now requires changes to proceed.Apr 8 2022, 6:37 PM
MaskRay added inline comments.Apr 8 2022, 7:39 PM
clang/lib/AST/Randstruct.cpp
157
clang/lib/Driver/ToolChains/Clang.cpp
5912

A->render(Args, CmdArgs);

5915

A->render(Args, CmdArgs);

clang/lib/Frontend/CompilerInvocation.cpp
4244

Why is -frandomize-layout-seed-file= needed? Can't the user use something like -frandomize-layout-seed=$(<file) ? Or backquotes for POSIX sh compatibility?

The impl uses the very uncommon header <fstream>.

clang/lib/Sema/SemaDecl.cpp
17976

32 may be too large. Consider the default inlined number of elements (fit the vector in 64 bytes).

clang/unittests/AST/RandstructTest.cpp
42
63
void added a comment.Apr 8 2022, 10:17 PM

Windows test is still failing after the std::shuffle => llvm::shuffle change, guess time for revert.

../../clang/unittests/AST/RandstructTest.cpp(165): error: Expected equality of these values:
  Expected
    Which is: { "lettuce", "bacon", "mayonnaise", "tomato" }
  getFieldNamesFromRecord(RD)
    Which is: { "bacon", "lettuce", "mayonnaise", "tomato" }
[  FAILED  ] StructureLayoutRandomization.MarkedRandomize (47 ms)
[----------] 1 test from StructureLayoutRandomization (47 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (47 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] StructureLayoutRandomization.MarkedRandomize

 1 FAILED TEST

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. 
********************
Failed Tests (1):
  Clang-Unit :: AST/./ASTTests.exe/StructureLayoutRandomization.MarkedRandomize

Did this fail after the test was removed? If not, then I don't appreciate you reverting my patch.

void added inline comments.Apr 8 2022, 10:25 PM
clang/lib/Frontend/CompilerInvocation.cpp
4244

That seems a bit clunky to me. If you don't like it, I can just remove the option entirely. Wish you would have mentioned these concerns earlier...like in the several weeks this has been in review.

The fstream header is used in other places. If there's a better alternative, please suggest one.

clang/lib/Sema/SemaDecl.cpp
17976

Linux has many structures with far more fields. In fact, it's probably not useful to randomize structures with a small number of fields.

clang/unittests/AST/RandstructTest.cpp
42

Nah.

void updated this revision to Diff 421692.Apr 8 2022, 11:35 PM

Fix test

MaskRay added inline comments.Apr 8 2022, 11:48 PM
clang/lib/Frontend/CompilerInvocation.cpp
4244

I was a subscriber only vaguely aware of this patch and mostly absent in the past 2 weeks on trips (which meant I spent really little time on reading patches) :)

I just hope that every option added is useful. A thing that is not so necessarily can be delayed until it is actually needed.

Just noticed that there is test coverage gap that the cc1 options are completely untested. There are unit tests, but no lit test.

aaron.ballman added inline comments.Apr 9 2022, 5:29 AM
clang/lib/Frontend/CompilerInvocation.cpp
4244

I just hope that every option added is useful. A thing that is not so necessarily can be delayed until it is actually needed.

I think this option is useful. Windows' cmd.exe doesn't make it particularly trivial to pipe contents to an argument in a command line, but also, IDEs don't always make it obvious how you would pipe the seed content into a file either. I don't see an issue with using fstream either; we use it when necessary.

clang/unittests/AST/RandstructTest.cpp
42

FWIW, I agree with this feedback -- please follow the coding standards unless there's strong incentive not to (which I don't think there is here). Sorry for not catching this before during review.

MaskRay added inline comments.Apr 9 2022, 12:22 PM
clang/lib/Frontend/CompilerInvocation.cpp
4244

Ah, LG!

Just need some tests for the two -f -cc1 options.

This revision was not accepted when it landed; it landed in state Needs Review.Apr 9 2022, 1:15 PM
This revision was automatically updated to reflect the committed changes.
jyknight added inline comments.
clang/unittests/AST/RandstructTest.cpp
155–159

I do think that as an ideal, a compile run on one host platform ought to produce the exact same output as a compile run on another (presuming a triple and sysroot are provided, and mumblemumble file-paths).

But I have no idea how close or far we currently are from such an ideal.

The relanded form still lacks the -f option testing I requested.

void added inline comments.Apr 11 2022, 3:28 PM
clang/unittests/AST/RandstructTest.cpp
155–159

I completely agree. Alternatively, we could use some other RNG-type algorithm that will be the same across platforms.

void added a comment.Apr 11 2022, 3:29 PM

The relanded form still lacks the -f option testing I requested.

The unit test tests the -frandomize-layout-seed= option already.

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

The relanded form still lacks the -f option testing I requested.

The unit test tests the -frandomize-layout-seed= option already.

OK, I see. Then test -frandomize-layout-seed-file= as well? I cannot find its test.

void added a comment.Apr 11 2022, 3:50 PM

The relanded form still lacks the -f option testing I requested.

The unit test tests the -frandomize-layout-seed= option already.

OK, I see. Then test -frandomize-layout-seed-file= as well? I cannot find its test.

Okay, I'll add a test for that.

void added a comment.Apr 11 2022, 4:05 PM

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

I wondered why the test did not fail again when you re-landed it. Now I see: you simply removed all order checks like EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));
The tests seem overly relaxing and no longer serve the original purposes to catch errors (if the algorithm is changed to not randomize at all, I suspect the tests will pass as well).

void added a comment.Apr 11 2022, 5:32 PM

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

So does it work or not? If I change it to llvm::shuffle, will the tests fail or will they pass regardless of the platform?

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

So does it work or not? If I change it to llvm::shuffle, will the tests fail or will they pass regardless of the platform?

If you change std::shuffle to llvm::shuffle and add back tests like EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));, the test will likely fail on Windows.
I recall that @aaron.ballman uses Windows and may help you find the differences.
I tend to agree with your I think it's just a case where Windows' algorithm for std::mt19937 is subtly different than the one for Linux.

void added a comment.Apr 12 2022, 1:10 AM

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

So does it work or not? If I change it to llvm::shuffle, will the tests fail or will they pass regardless of the platform?

If you change std::shuffle to llvm::shuffle and add back tests like EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));, the test will likely fail on Windows.
I recall that @aaron.ballman uses Windows and may help you find the differences.

It was also failing on MacOS. And it failed a different way on another Windows version. That's why I removed the test for the deterministic shuffle.

I tend to agree with your I think it's just a case where Windows' algorithm for std::mt19937 is subtly different than the one for Linux.

The only other option would be to add the EXPECT_* stuff on one platform (like Linux). I suppose that would be better than nothing.

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

So does it work or not? If I change it to llvm::shuffle, will the tests fail or will they pass regardless of the platform?

If you change std::shuffle to llvm::shuffle and add back tests like EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));, the test will likely fail on Windows.
I recall that @aaron.ballman uses Windows and may help you find the differences.

It was also failing on MacOS. And it failed a different way on another Windows version. That's why I removed the test for the deterministic shuffle.

I tend to agree with your I think it's just a case where Windows' algorithm for std::mt19937 is subtly different than the one for Linux.

The only other option would be to add the EXPECT_* stuff on one platform (like Linux). I suppose that would be better than nothing.

Here's what has me confused... You're using std::mt19937 which is a very specific random number algorithm and you're giving it the same seed. I don't think we *should* be getting different behavior from the random number generator across platforms. The issue is the call to std::shuffle (see https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Notes), so I think using llvm::shuffle will fix all the tests on all the platforms.

void added a comment.Apr 12 2022, 11:00 AM

7aa8c38a9e190aea14116028c38b1d9f54cbb0b3 still uses std::shuffle, not incorporating the llvm::shuffle fixes I did.

You said it was still failing after the std::shuffle to llvm::shuffle change.

By saying it still failed, I meant there were other Windows vs non-Windows differences, not that std::shuffle=>llvm::shuffle was an unintended change.

So does it work or not? If I change it to llvm::shuffle, will the tests fail or will they pass regardless of the platform?

If you change std::shuffle to llvm::shuffle and add back tests like EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));, the test will likely fail on Windows.
I recall that @aaron.ballman uses Windows and may help you find the differences.

It was also failing on MacOS. And it failed a different way on another Windows version. That's why I removed the test for the deterministic shuffle.

I tend to agree with your I think it's just a case where Windows' algorithm for std::mt19937 is subtly different than the one for Linux.

The only other option would be to add the EXPECT_* stuff on one platform (like Linux). I suppose that would be better than nothing.

Here's what has me confused... You're using std::mt19937 which is a very specific random number algorithm and you're giving it the same seed. I don't think we *should* be getting different behavior from the random number generator across platforms. The issue is the call to std::shuffle (see https://en.cppreference.com/w/cpp/algorithm/random_shuffle#Notes), so I think using llvm::shuffle will fix all the tests on all the platforms.

Okay. So I'll make this change and submit it during a time when there isn't a lot of activity so that I can revert it if it fails without annoying too many people.