xref: /llvm-project/clang/unittests/AST/RandstructTest.cpp (revision 6f79700830292d86afec5f3cf5143b00e6f3f1fd)
17aa8c38aSConnor Kuehl //===- unittest/AST/RandstructTest.cpp ------------------------------------===//
27aa8c38aSConnor Kuehl //
37aa8c38aSConnor Kuehl // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47aa8c38aSConnor Kuehl // See https://llvm.org/LICENSE.txt for license information.
57aa8c38aSConnor Kuehl // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67aa8c38aSConnor Kuehl //
77aa8c38aSConnor Kuehl //===----------------------------------------------------------------------===//
87aa8c38aSConnor Kuehl //
97aa8c38aSConnor Kuehl // This file contains tests for Clang's structure field layout randomization.
107aa8c38aSConnor Kuehl //
117aa8c38aSConnor Kuehl //===----------------------------------------------------------------------===//
127aa8c38aSConnor Kuehl 
137aa8c38aSConnor Kuehl /*
147aa8c38aSConnor Kuehl  * Build this test suite by running `make ASTTests` in the build folder.
157aa8c38aSConnor Kuehl  *
167aa8c38aSConnor Kuehl  * Run this test suite by running the following in the build folder:
177aa8c38aSConnor Kuehl  * ` ./tools/clang/unittests/AST/ASTTests
188c77a75fSBill Wendling  * --gtest_filter=RecordLayoutRandomization*`
197aa8c38aSConnor Kuehl  */
207aa8c38aSConnor Kuehl 
217aa8c38aSConnor Kuehl #include "clang/AST/Randstruct.h"
227aa8c38aSConnor Kuehl #include "gtest/gtest.h"
237aa8c38aSConnor Kuehl 
247aa8c38aSConnor Kuehl #include "DeclMatcher.h"
257aa8c38aSConnor Kuehl #include "clang/AST/RecordLayout.h"
267aa8c38aSConnor Kuehl #include "clang/ASTMatchers/ASTMatchers.h"
277aa8c38aSConnor Kuehl #include "clang/Frontend/ASTUnit.h"
287aa8c38aSConnor Kuehl #include "clang/Testing/CommandLineArgs.h"
297aa8c38aSConnor Kuehl #include "clang/Tooling/Tooling.h"
308c77a75fSBill Wendling #include "llvm/Support/ToolOutputFile.h"
317aa8c38aSConnor Kuehl 
327aa8c38aSConnor Kuehl #include <vector>
337aa8c38aSConnor Kuehl 
347aa8c38aSConnor Kuehl using namespace clang;
357aa8c38aSConnor Kuehl using namespace clang::ast_matchers;
367aa8c38aSConnor Kuehl using namespace clang::randstruct;
377aa8c38aSConnor Kuehl 
387aa8c38aSConnor Kuehl using field_names = std::vector<std::string>;
397aa8c38aSConnor Kuehl 
408c77a75fSBill Wendling constexpr const char Seed[] = "1234567890abcdef";
417aa8c38aSConnor Kuehl 
getRecordDeclFromAST(const ASTContext & C,const std::string & Name)4277e71bcfSBill Wendling static RecordDecl *getRecordDeclFromAST(const ASTContext &C,
4377e71bcfSBill Wendling                                         const std::string &Name) {
447aa8c38aSConnor Kuehl   RecordDecl *RD = FirstDeclMatcher<RecordDecl>().match(
457aa8c38aSConnor Kuehl       C.getTranslationUnitDecl(), recordDecl(hasName(Name)));
467aa8c38aSConnor Kuehl   return RD;
477aa8c38aSConnor Kuehl }
487aa8c38aSConnor Kuehl 
getFieldNamesFromRecord(const RecordDecl * RD)4977e71bcfSBill Wendling static std::vector<std::string> getFieldNamesFromRecord(const RecordDecl *RD) {
507aa8c38aSConnor Kuehl   std::vector<std::string> Fields;
517aa8c38aSConnor Kuehl 
527aa8c38aSConnor Kuehl   Fields.reserve(8);
537aa8c38aSConnor Kuehl   for (auto *Field : RD->fields())
547aa8c38aSConnor Kuehl     Fields.push_back(Field->getNameAsString());
557aa8c38aSConnor Kuehl 
567aa8c38aSConnor Kuehl   return Fields;
577aa8c38aSConnor Kuehl }
587aa8c38aSConnor Kuehl 
isSubsequence(const field_names & Seq,const field_names & Subseq)5977e71bcfSBill Wendling static bool isSubsequence(const field_names &Seq, const field_names &Subseq) {
607aa8c38aSConnor Kuehl   unsigned SeqLen = Seq.size();
617aa8c38aSConnor Kuehl   unsigned SubLen = Subseq.size();
627aa8c38aSConnor Kuehl 
637aa8c38aSConnor Kuehl   bool IsSubseq = false;
647aa8c38aSConnor Kuehl   for (unsigned I = 0; I < SeqLen; ++I)
657aa8c38aSConnor Kuehl     if (Seq[I] == Subseq[0]) {
667aa8c38aSConnor Kuehl       IsSubseq = true;
677aa8c38aSConnor Kuehl       for (unsigned J = 0; J + I < SeqLen && J < SubLen; ++J) {
687aa8c38aSConnor Kuehl         if (Seq[J + I] != Subseq[J]) {
697aa8c38aSConnor Kuehl           IsSubseq = false;
707aa8c38aSConnor Kuehl           break;
717aa8c38aSConnor Kuehl         }
727aa8c38aSConnor Kuehl       }
737aa8c38aSConnor Kuehl     }
747aa8c38aSConnor Kuehl 
757aa8c38aSConnor Kuehl   return IsSubseq;
767aa8c38aSConnor Kuehl }
777aa8c38aSConnor Kuehl 
recordsEqual(const std::unique_ptr<ASTUnit> & LHS,const std::unique_ptr<ASTUnit> & RHS,const std::string & RecordName)788c77a75fSBill Wendling static bool recordsEqual(const std::unique_ptr<ASTUnit> &LHS,
798c77a75fSBill Wendling                          const std::unique_ptr<ASTUnit> &RHS,
808c77a75fSBill Wendling                          const std::string &RecordName) {
818c77a75fSBill Wendling   const RecordDecl *LHSRD =
828c77a75fSBill Wendling       getRecordDeclFromAST(LHS->getASTContext(), RecordName);
838c77a75fSBill Wendling   const RecordDecl *RHSRD =
848c77a75fSBill Wendling       getRecordDeclFromAST(LHS->getASTContext(), RecordName);
858c77a75fSBill Wendling 
868c77a75fSBill Wendling   return getFieldNamesFromRecord(LHSRD) == getFieldNamesFromRecord(RHSRD);
878c77a75fSBill Wendling }
888c77a75fSBill Wendling 
898c77a75fSBill Wendling static std::unique_ptr<ASTUnit>
makeAST(const std::string & SourceCode,bool ExpectError=false,std::vector<std::string> RecordNames=std::vector<std::string> ())908c77a75fSBill Wendling makeAST(const std::string &SourceCode, bool ExpectError = false,
918c77a75fSBill Wendling         std::vector<std::string> RecordNames = std::vector<std::string>()) {
928c77a75fSBill Wendling   std::vector<std::string> Args = getCommandLineArgsForTesting(Lang_C99);
938c77a75fSBill Wendling   Args.push_back("-frandomize-layout-seed=" + std::string(Seed));
948c77a75fSBill Wendling 
958c77a75fSBill Wendling   IgnoringDiagConsumer IgnoringConsumer = IgnoringDiagConsumer();
968c77a75fSBill Wendling 
978c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs(
988c77a75fSBill Wendling       SourceCode, Args, "input.c", "clang-tool",
998c77a75fSBill Wendling       std::make_shared<PCHContainerOperations>(),
1008c77a75fSBill Wendling       tooling::getClangStripDependencyFileAdjuster(),
1018c77a75fSBill Wendling       tooling::FileContentMappings(), &IgnoringConsumer);
1028c77a75fSBill Wendling 
1038c77a75fSBill Wendling   int SeedFileFD = -1;
1048c77a75fSBill Wendling   llvm::SmallString<256> SeedFilename;
1058c77a75fSBill Wendling   EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("seed", "rng", SeedFileFD,
1068c77a75fSBill Wendling                                                   SeedFilename));
1078c77a75fSBill Wendling   llvm::ToolOutputFile SeedFile(SeedFilename, SeedFileFD);
1088c77a75fSBill Wendling   SeedFile.os() << Seed << "\n";
1098c77a75fSBill Wendling 
1108c77a75fSBill Wendling   Args.clear();
1118c77a75fSBill Wendling   Args = getCommandLineArgsForTesting(Lang_C99);
1128c77a75fSBill Wendling   Args.push_back("-frandomize-layout-seed-file=" +
1138c77a75fSBill Wendling                  SeedFile.getFilename().str());
1148c77a75fSBill Wendling 
1158c77a75fSBill Wendling   std::unique_ptr<ASTUnit> ASTFileSeed = tooling::buildASTFromCodeWithArgs(
1168c77a75fSBill Wendling       SourceCode, Args, "input.c", "clang-tool",
1178c77a75fSBill Wendling       std::make_shared<PCHContainerOperations>(),
1188c77a75fSBill Wendling       tooling::getClangStripDependencyFileAdjuster(),
1198c77a75fSBill Wendling       tooling::FileContentMappings(), &IgnoringConsumer);
1208c77a75fSBill Wendling 
1218c77a75fSBill Wendling   if (!ExpectError) {
1228c77a75fSBill Wendling     if (RecordNames.empty())
1238c77a75fSBill Wendling       RecordNames.push_back("test");
1248c77a75fSBill Wendling 
1258c77a75fSBill Wendling     for (std::string Name : RecordNames)
1268c77a75fSBill Wendling       EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, Name));
1278c77a75fSBill Wendling   }
1288c77a75fSBill Wendling 
1298c77a75fSBill Wendling   return AST;
1308c77a75fSBill Wendling }
1318c77a75fSBill Wendling 
1327aa8c38aSConnor Kuehl namespace clang {
1337aa8c38aSConnor Kuehl namespace ast_matchers {
1347aa8c38aSConnor Kuehl 
declCount(const RecordDecl * RD)135463790bfSBill Wendling long declCount(const RecordDecl *RD) {
136463790bfSBill Wendling   return llvm::count_if(RD->decls(), [&](const Decl *D) {
137463790bfSBill Wendling     return isa<FieldDecl>(D) || isa<RecordDecl>(D);
138463790bfSBill Wendling   });
139463790bfSBill Wendling }
140463790bfSBill Wendling 
1418c77a75fSBill Wendling #define RANDSTRUCT_TEST_SUITE_TEST RecordLayoutRandomizationTestSuiteTest
1427aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST_SUITE_TEST,CanDetermineIfSubsequenceExists)1437aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST_SUITE_TEST, CanDetermineIfSubsequenceExists) {
1447aa8c38aSConnor Kuehl   const field_names Seq = {"a", "b", "c", "d"};
1457aa8c38aSConnor Kuehl 
1467aa8c38aSConnor Kuehl   EXPECT_TRUE(isSubsequence(Seq, {"b", "c"}));
1477aa8c38aSConnor Kuehl   EXPECT_TRUE(isSubsequence(Seq, {"a", "b", "c", "d"}));
1487aa8c38aSConnor Kuehl   EXPECT_TRUE(isSubsequence(Seq, {"b", "c", "d"}));
1497aa8c38aSConnor Kuehl   EXPECT_TRUE(isSubsequence(Seq, {"a"}));
1507aa8c38aSConnor Kuehl   EXPECT_FALSE(isSubsequence(Seq, {"a", "d"}));
1517aa8c38aSConnor Kuehl }
1527aa8c38aSConnor Kuehl 
1538c77a75fSBill Wendling #define RANDSTRUCT_TEST RecordLayoutRandomization
1547aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,UnmarkedStruct)1557aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, UnmarkedStruct) {
1568c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
1577aa8c38aSConnor Kuehl     struct test {
1587aa8c38aSConnor Kuehl         int bacon;
1597aa8c38aSConnor Kuehl         long lettuce;
1607aa8c38aSConnor Kuehl         long long tomato;
1617aa8c38aSConnor Kuehl         float mayonnaise;
1627aa8c38aSConnor Kuehl     };
1637aa8c38aSConnor Kuehl   )c");
1647aa8c38aSConnor Kuehl 
1657aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
1667aa8c38aSConnor Kuehl 
1677aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
168463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
1697aa8c38aSConnor Kuehl 
1707aa8c38aSConnor Kuehl   EXPECT_FALSE(RD->hasAttr<RandomizeLayoutAttr>());
1717aa8c38aSConnor Kuehl   EXPECT_FALSE(RD->isRandomized());
172463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
1737aa8c38aSConnor Kuehl }
1747aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,MarkedNoRandomize)1757aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, MarkedNoRandomize) {
1768c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
1777aa8c38aSConnor Kuehl     struct test {
1787aa8c38aSConnor Kuehl         int bacon;
1797aa8c38aSConnor Kuehl         long lettuce;
1807aa8c38aSConnor Kuehl         long long tomato;
1817aa8c38aSConnor Kuehl         float mayonnaise;
1827aa8c38aSConnor Kuehl     } __attribute__((no_randomize_layout));
1837aa8c38aSConnor Kuehl   )c");
1847aa8c38aSConnor Kuehl 
1857aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
1867aa8c38aSConnor Kuehl 
1877aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
188463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
1897aa8c38aSConnor Kuehl 
1907aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->hasAttr<NoRandomizeLayoutAttr>());
1917aa8c38aSConnor Kuehl   EXPECT_FALSE(RD->isRandomized());
192463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
1937aa8c38aSConnor Kuehl }
1947aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,MarkedRandomize)1957aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, MarkedRandomize) {
1968c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
1977aa8c38aSConnor Kuehl     struct test {
1987aa8c38aSConnor Kuehl         int bacon;
1997aa8c38aSConnor Kuehl         long lettuce;
2007aa8c38aSConnor Kuehl         long long tomato;
2017aa8c38aSConnor Kuehl         float mayonnaise;
2027aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
2037aa8c38aSConnor Kuehl   )c");
2047aa8c38aSConnor Kuehl 
2057aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
2067aa8c38aSConnor Kuehl 
2077aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
208463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
2097aa8c38aSConnor Kuehl 
2107aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->hasAttr<RandomizeLayoutAttr>());
2117aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->isRandomized());
212463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
2137aa8c38aSConnor Kuehl }
2147aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,MismatchedAttrsDeclVsDef)2157aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, MismatchedAttrsDeclVsDef) {
2168c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
2177aa8c38aSConnor Kuehl     struct test __attribute__((randomize_layout));
2187aa8c38aSConnor Kuehl     struct test {
2197aa8c38aSConnor Kuehl         int bacon;
2207aa8c38aSConnor Kuehl         long lettuce;
2217aa8c38aSConnor Kuehl         long long tomato;
2227aa8c38aSConnor Kuehl         float mayonnaise;
2237aa8c38aSConnor Kuehl     } __attribute__((no_randomize_layout));
2248dbc6b56SNico Weber   )c",
2258dbc6b56SNico Weber                                          true);
2267aa8c38aSConnor Kuehl 
2277aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
2287aa8c38aSConnor Kuehl 
2298c77a75fSBill Wendling   const DiagnosticsEngine &Diags = AST->getDiagnostics();
2307aa8c38aSConnor Kuehl 
2317aa8c38aSConnor Kuehl   EXPECT_FALSE(Diags.hasFatalErrorOccurred());
2327aa8c38aSConnor Kuehl   EXPECT_FALSE(Diags.hasUncompilableErrorOccurred());
2337aa8c38aSConnor Kuehl   EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
2347aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumWarnings(), 1u);
2357aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumErrors(), 0u);
2367aa8c38aSConnor Kuehl }
2377aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,MismatchedAttrsRandomizeVsNoRandomize)2387aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, MismatchedAttrsRandomizeVsNoRandomize) {
2398c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
2408c77a75fSBill Wendling     struct test {
2417aa8c38aSConnor Kuehl         int bacon;
2427aa8c38aSConnor Kuehl         long lettuce;
2437aa8c38aSConnor Kuehl         long long tomato;
2447aa8c38aSConnor Kuehl         float mayonnaise;
2457aa8c38aSConnor Kuehl     } __attribute__((randomize_layout)) __attribute__((no_randomize_layout));
2468dbc6b56SNico Weber   )c",
2478dbc6b56SNico Weber                                          true);
2487aa8c38aSConnor Kuehl 
2497aa8c38aSConnor Kuehl   EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred());
2507aa8c38aSConnor Kuehl 
2518c77a75fSBill Wendling   const DiagnosticsEngine &Diags = AST->getDiagnostics();
2527aa8c38aSConnor Kuehl 
2537aa8c38aSConnor Kuehl   EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
2547aa8c38aSConnor Kuehl   EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
2557aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumWarnings(), 0u);
2567aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumErrors(), 1u);
2577aa8c38aSConnor Kuehl }
2587aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,MismatchedAttrsNoRandomizeVsRandomize)2597aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, MismatchedAttrsNoRandomizeVsRandomize) {
2608c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
2617aa8c38aSConnor Kuehl     struct test3 {
2627aa8c38aSConnor Kuehl         int bacon;
2637aa8c38aSConnor Kuehl         long lettuce;
2647aa8c38aSConnor Kuehl         long long tomato;
2657aa8c38aSConnor Kuehl         float mayonnaise;
2667aa8c38aSConnor Kuehl     } __attribute__((no_randomize_layout)) __attribute__((randomize_layout));
2678dbc6b56SNico Weber   )c",
2688dbc6b56SNico Weber                                          true);
2697aa8c38aSConnor Kuehl 
2707aa8c38aSConnor Kuehl   EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred());
2717aa8c38aSConnor Kuehl 
2728c77a75fSBill Wendling   const DiagnosticsEngine &Diags = AST->getDiagnostics();
2737aa8c38aSConnor Kuehl 
2747aa8c38aSConnor Kuehl   EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
2757aa8c38aSConnor Kuehl   EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
2767aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumWarnings(), 0u);
2777aa8c38aSConnor Kuehl   EXPECT_EQ(Diags.getNumErrors(), 1u);
2787aa8c38aSConnor Kuehl }
2797aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,CheckAdjacentBitfieldsRemainAdjacentAfterRandomization)2807aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, CheckAdjacentBitfieldsRemainAdjacentAfterRandomization) {
2818c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
2827aa8c38aSConnor Kuehl     struct test {
2837aa8c38aSConnor Kuehl         int a;
2847aa8c38aSConnor Kuehl         int b;
2857aa8c38aSConnor Kuehl         int x : 1;
2867aa8c38aSConnor Kuehl         int y : 1;
2877aa8c38aSConnor Kuehl         int z : 1;
2887aa8c38aSConnor Kuehl         int c;
2897aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
2907aa8c38aSConnor Kuehl   )c");
2917aa8c38aSConnor Kuehl 
2927aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
2937aa8c38aSConnor Kuehl 
2947aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
295463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
296463790bfSBill Wendling 
2978dbc6b56SNico Weber   const field_names Actual = getFieldNamesFromRecord(RD);
2988dbc6b56SNico Weber   const field_names Subseq = {"x", "y", "z"};
2997aa8c38aSConnor Kuehl 
3007aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->isRandomized());
3018dbc6b56SNico Weber   EXPECT_TRUE(isSubsequence(Actual, Subseq));
302463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
3037aa8c38aSConnor Kuehl }
3047aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,CheckFlexibleArrayMemberRemainsAtEndOfStructure1)305463790bfSBill Wendling TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure1) {
3068c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
3077aa8c38aSConnor Kuehl     struct test {
3087aa8c38aSConnor Kuehl         int a;
309463790bfSBill Wendling         int b;
310463790bfSBill Wendling         int c;
311463790bfSBill Wendling         int d;
312463790bfSBill Wendling         int e;
313463790bfSBill Wendling         int f;
314463790bfSBill Wendling         int g;
315463790bfSBill Wendling         int h;
3167aa8c38aSConnor Kuehl         char name[];
3177aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
3187aa8c38aSConnor Kuehl   )c");
3197aa8c38aSConnor Kuehl 
3207aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
3217aa8c38aSConnor Kuehl 
3227aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
323463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
3247aa8c38aSConnor Kuehl 
325463790bfSBill Wendling   EXPECT_TRUE(RD->hasFlexibleArrayMember());
3267aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->isRandomized());
327463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
328463790bfSBill Wendling   EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
329463790bfSBill Wendling }
330463790bfSBill Wendling 
TEST(RANDSTRUCT_TEST,CheckFlexibleArrayMemberRemainsAtEndOfStructure2)331463790bfSBill Wendling TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure2) {
332463790bfSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
333463790bfSBill Wendling     struct test {
334463790bfSBill Wendling         int a;
335463790bfSBill Wendling         int b;
336463790bfSBill Wendling         int c;
337463790bfSBill Wendling         int d;
338463790bfSBill Wendling         int e;
339463790bfSBill Wendling         int f;
340463790bfSBill Wendling         int g;
341463790bfSBill Wendling         int h;
342463790bfSBill Wendling         char name[0];
343463790bfSBill Wendling     } __attribute__((randomize_layout));
344463790bfSBill Wendling   )c");
345463790bfSBill Wendling 
346463790bfSBill Wendling   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
347463790bfSBill Wendling 
348463790bfSBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
349463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
350463790bfSBill Wendling 
351463790bfSBill Wendling   EXPECT_FALSE(RD->hasFlexibleArrayMember());
352463790bfSBill Wendling   EXPECT_TRUE(RD->isRandomized());
353463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
354463790bfSBill Wendling   EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
355463790bfSBill Wendling }
356463790bfSBill Wendling 
TEST(RANDSTRUCT_TEST,CheckFlexibleArrayMemberRemainsAtEndOfStructure3)357463790bfSBill Wendling TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure3) {
358463790bfSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
359463790bfSBill Wendling     struct test {
360463790bfSBill Wendling         int a;
361463790bfSBill Wendling         int b;
362463790bfSBill Wendling         int c;
363463790bfSBill Wendling         int d;
364463790bfSBill Wendling         int e;
365463790bfSBill Wendling         int f;
366463790bfSBill Wendling         int g;
367463790bfSBill Wendling         int h;
368463790bfSBill Wendling         char name[1];
369463790bfSBill Wendling     } __attribute__((randomize_layout));
370463790bfSBill Wendling   )c");
371463790bfSBill Wendling 
372463790bfSBill Wendling   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
373463790bfSBill Wendling 
374463790bfSBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
375463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
376463790bfSBill Wendling 
377463790bfSBill Wendling   EXPECT_FALSE(RD->hasFlexibleArrayMember());
378463790bfSBill Wendling   EXPECT_TRUE(RD->isRandomized());
379463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
380463790bfSBill Wendling   EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
3817aa8c38aSConnor Kuehl }
3827aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,RandstructDoesNotOverrideThePackedAttr)3837aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, RandstructDoesNotOverrideThePackedAttr) {
3848c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST =
3858c77a75fSBill Wendling       makeAST(R"c(
3867aa8c38aSConnor Kuehl     struct test_struct {
3877aa8c38aSConnor Kuehl         char a;
3887aa8c38aSConnor Kuehl         float b[3];
3897aa8c38aSConnor Kuehl         short c;
3907aa8c38aSConnor Kuehl         int d;
3917aa8c38aSConnor Kuehl     } __attribute__((packed, randomize_layout));
3927aa8c38aSConnor Kuehl 
3937aa8c38aSConnor Kuehl     struct another_struct {
3947aa8c38aSConnor Kuehl         char a;
3957aa8c38aSConnor Kuehl         char b[5];
3967aa8c38aSConnor Kuehl         int c;
3977aa8c38aSConnor Kuehl     } __attribute__((packed, randomize_layout));
3987aa8c38aSConnor Kuehl 
3997aa8c38aSConnor Kuehl     struct last_struct {
4007aa8c38aSConnor Kuehl         char a;
4017aa8c38aSConnor Kuehl         long long b;
4027aa8c38aSConnor Kuehl         int c[];
4037aa8c38aSConnor Kuehl     } __attribute__((packed, randomize_layout));
4048dbc6b56SNico Weber   )c",
4058dbc6b56SNico Weber               false,
4068dbc6b56SNico Weber               std::vector<std::string>(
4078dbc6b56SNico Weber                   {"test_struct", "another_struct", "last_struct"}));
4087aa8c38aSConnor Kuehl 
4097aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
4107aa8c38aSConnor Kuehl 
4117aa8c38aSConnor Kuehl   // FIXME (?): calling getASTRecordLayout is probably a necessary evil so that
4127aa8c38aSConnor Kuehl   // Clang's RecordBuilders can actually flesh out the information like
4137aa8c38aSConnor Kuehl   // alignment, etc.
4147aa8c38aSConnor Kuehl   {
4157aa8c38aSConnor Kuehl     const RecordDecl *RD =
4167aa8c38aSConnor Kuehl         getRecordDeclFromAST(AST->getASTContext(), "test_struct");
4177aa8c38aSConnor Kuehl     const ASTRecordLayout *Layout =
4187aa8c38aSConnor Kuehl         &AST->getASTContext().getASTRecordLayout(RD);
419463790bfSBill Wendling     long OriginalDeclCount = declCount(RD);
4207aa8c38aSConnor Kuehl 
4217aa8c38aSConnor Kuehl     EXPECT_TRUE(RD->isRandomized());
4227aa8c38aSConnor Kuehl     EXPECT_EQ(19, Layout->getSize().getQuantity());
423463790bfSBill Wendling     EXPECT_EQ(OriginalDeclCount, declCount(RD));
4247aa8c38aSConnor Kuehl   }
4257aa8c38aSConnor Kuehl 
4267aa8c38aSConnor Kuehl   {
4277aa8c38aSConnor Kuehl     const RecordDecl *RD =
4287aa8c38aSConnor Kuehl         getRecordDeclFromAST(AST->getASTContext(), "another_struct");
4297aa8c38aSConnor Kuehl     const ASTRecordLayout *Layout =
4307aa8c38aSConnor Kuehl         &AST->getASTContext().getASTRecordLayout(RD);
431463790bfSBill Wendling     long OriginalDeclCount = declCount(RD);
4327aa8c38aSConnor Kuehl 
4337aa8c38aSConnor Kuehl     EXPECT_TRUE(RD->isRandomized());
4347aa8c38aSConnor Kuehl     EXPECT_EQ(10, Layout->getSize().getQuantity());
435463790bfSBill Wendling     EXPECT_EQ(OriginalDeclCount, declCount(RD));
4367aa8c38aSConnor Kuehl   }
4377aa8c38aSConnor Kuehl 
4387aa8c38aSConnor Kuehl   {
4397aa8c38aSConnor Kuehl     const RecordDecl *RD =
4407aa8c38aSConnor Kuehl         getRecordDeclFromAST(AST->getASTContext(), "last_struct");
4417aa8c38aSConnor Kuehl     const ASTRecordLayout *Layout =
4427aa8c38aSConnor Kuehl         &AST->getASTContext().getASTRecordLayout(RD);
443463790bfSBill Wendling     long OriginalDeclCount = declCount(RD);
4447aa8c38aSConnor Kuehl 
4457aa8c38aSConnor Kuehl     EXPECT_TRUE(RD->isRandomized());
4467aa8c38aSConnor Kuehl     EXPECT_EQ(9, Layout->getSize().getQuantity());
447463790bfSBill Wendling     EXPECT_EQ(OriginalDeclCount, declCount(RD));
4487aa8c38aSConnor Kuehl   }
4497aa8c38aSConnor Kuehl }
4507aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,ZeroWidthBitfieldsSeparateAllocationUnits)4517aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, ZeroWidthBitfieldsSeparateAllocationUnits) {
4528c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
4537aa8c38aSConnor Kuehl     struct test {
4547aa8c38aSConnor Kuehl         int a : 1;
4557aa8c38aSConnor Kuehl         int   : 0;
4567aa8c38aSConnor Kuehl         int b : 1;
4577aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
4587aa8c38aSConnor Kuehl   )c");
4597aa8c38aSConnor Kuehl 
4607aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
4617aa8c38aSConnor Kuehl 
4627aa8c38aSConnor Kuehl   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
463463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
4647aa8c38aSConnor Kuehl 
4657aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->isRandomized());
466463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
4677aa8c38aSConnor Kuehl }
4687aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,RandstructDoesNotRandomizeUnionFieldOrder)4697aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, RandstructDoesNotRandomizeUnionFieldOrder) {
4708c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
4718c77a75fSBill Wendling     union test {
4727aa8c38aSConnor Kuehl         int a;
4737aa8c38aSConnor Kuehl         int b;
4747aa8c38aSConnor Kuehl         int c;
4757aa8c38aSConnor Kuehl         int d;
4767aa8c38aSConnor Kuehl         int e;
4777aa8c38aSConnor Kuehl         int f;
4787aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
4797aa8c38aSConnor Kuehl   )c");
4807aa8c38aSConnor Kuehl 
4817aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
4827aa8c38aSConnor Kuehl 
483463790bfSBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
484463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
4857aa8c38aSConnor Kuehl 
4867aa8c38aSConnor Kuehl   EXPECT_FALSE(RD->isRandomized());
487463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
4887aa8c38aSConnor Kuehl }
4897aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,AnonymousStructsAndUnionsRetainFieldOrder)4907aa8c38aSConnor Kuehl TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) {
4918c77a75fSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
4928c77a75fSBill Wendling     struct test {
4937aa8c38aSConnor Kuehl         int a;
4947aa8c38aSConnor Kuehl         struct sub_struct {
4957aa8c38aSConnor Kuehl             int b;
4967aa8c38aSConnor Kuehl             int c;
4977aa8c38aSConnor Kuehl             int d;
4987aa8c38aSConnor Kuehl             int e;
4997aa8c38aSConnor Kuehl             int f;
5007aa8c38aSConnor Kuehl         } __attribute__((randomize_layout)) s;
5017aa8c38aSConnor Kuehl         int f;
5027aa8c38aSConnor Kuehl         struct {
5037aa8c38aSConnor Kuehl             int g;
5047aa8c38aSConnor Kuehl             int h;
5057aa8c38aSConnor Kuehl             int i;
5067aa8c38aSConnor Kuehl             int j;
5077aa8c38aSConnor Kuehl             int k;
5087aa8c38aSConnor Kuehl         };
5097aa8c38aSConnor Kuehl         int l;
5107aa8c38aSConnor Kuehl         union {
5117aa8c38aSConnor Kuehl             int m;
5127aa8c38aSConnor Kuehl             int n;
5137aa8c38aSConnor Kuehl             int o;
5147aa8c38aSConnor Kuehl             int p;
5157aa8c38aSConnor Kuehl             int q;
5167aa8c38aSConnor Kuehl         };
5177aa8c38aSConnor Kuehl         int r;
5187aa8c38aSConnor Kuehl     } __attribute__((randomize_layout));
5197aa8c38aSConnor Kuehl   )c");
5207aa8c38aSConnor Kuehl 
5217aa8c38aSConnor Kuehl   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
5227aa8c38aSConnor Kuehl 
5238c77a75fSBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
524463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
5257aa8c38aSConnor Kuehl 
5267aa8c38aSConnor Kuehl   EXPECT_TRUE(RD->isRandomized());
527463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
5287aa8c38aSConnor Kuehl 
5297aa8c38aSConnor Kuehl   bool AnonStructTested = false;
5307aa8c38aSConnor Kuehl   bool AnonUnionTested = false;
5317aa8c38aSConnor Kuehl 
5327aa8c38aSConnor Kuehl   for (const Decl *D : RD->decls())
5337aa8c38aSConnor Kuehl     if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
5347aa8c38aSConnor Kuehl       if (const auto *Record = FD->getType()->getAs<RecordType>()) {
5357aa8c38aSConnor Kuehl         RD = Record->getDecl();
5367aa8c38aSConnor Kuehl         if (RD->isAnonymousStructOrUnion()) {
5377aa8c38aSConnor Kuehl           // These field orders shouldn't change.
5387aa8c38aSConnor Kuehl           if (RD->isUnion()) {
5397aa8c38aSConnor Kuehl             const field_names Expected = {"m", "n", "o", "p", "q"};
5407aa8c38aSConnor Kuehl 
5417aa8c38aSConnor Kuehl             EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));
5427aa8c38aSConnor Kuehl             AnonUnionTested = true;
5437aa8c38aSConnor Kuehl           } else {
5447aa8c38aSConnor Kuehl             const field_names Expected = {"g", "h", "i", "j", "k"};
5457aa8c38aSConnor Kuehl 
5467aa8c38aSConnor Kuehl             EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));
5477aa8c38aSConnor Kuehl             AnonStructTested = true;
5487aa8c38aSConnor Kuehl           }
5497aa8c38aSConnor Kuehl         }
5507aa8c38aSConnor Kuehl       }
5517aa8c38aSConnor Kuehl     }
5527aa8c38aSConnor Kuehl 
5537aa8c38aSConnor Kuehl   EXPECT_TRUE(AnonStructTested);
5547aa8c38aSConnor Kuehl   EXPECT_TRUE(AnonUnionTested);
5557aa8c38aSConnor Kuehl }
5567aa8c38aSConnor Kuehl 
TEST(RANDSTRUCT_TEST,AnonymousStructsAndUnionsReferenced)557463790bfSBill Wendling TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsReferenced) {
558463790bfSBill Wendling   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
559463790bfSBill Wendling     struct test {
560463790bfSBill Wendling         int bacon;
561463790bfSBill Wendling         long lettuce;
562463790bfSBill Wendling         struct { double avocado; char blech; };
563463790bfSBill Wendling         long long tomato;
564463790bfSBill Wendling         union { char toast[8]; unsigned toast_thing; };
565463790bfSBill Wendling         float mayonnaise;
566463790bfSBill Wendling     } __attribute__((randomize_layout));
567463790bfSBill Wendling 
568463790bfSBill Wendling     int foo(struct test *t) {
569463790bfSBill Wendling       return t->blech;
570463790bfSBill Wendling     }
571463790bfSBill Wendling 
572463790bfSBill Wendling     char *bar(struct test *t) {
573463790bfSBill Wendling       return t->toast;
574463790bfSBill Wendling     }
575463790bfSBill Wendling   )c");
576463790bfSBill Wendling 
577463790bfSBill Wendling   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
578463790bfSBill Wendling 
579463790bfSBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
580463790bfSBill Wendling   long OriginalDeclCount = declCount(RD);
581463790bfSBill Wendling 
582463790bfSBill Wendling   EXPECT_TRUE(RD->isRandomized());
583463790bfSBill Wendling   EXPECT_EQ(OriginalDeclCount, declCount(RD));
584463790bfSBill Wendling }
585463790bfSBill Wendling 
TEST(RANDSTRUCT_TEST,AutoRandomizeStructOfFunctionPointers)586*6f797008SBill Wendling TEST(RANDSTRUCT_TEST, AutoRandomizeStructOfFunctionPointers) {
587*6f797008SBill Wendling   const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
588*6f797008SBill Wendling     typedef void (*func_ptr)();
589*6f797008SBill Wendling 
590*6f797008SBill Wendling     struct test {
591*6f797008SBill Wendling       func_ptr a;
592*6f797008SBill Wendling       func_ptr b;
593*6f797008SBill Wendling       func_ptr c;
594*6f797008SBill Wendling       func_ptr d;
595*6f797008SBill Wendling       func_ptr e;
596*6f797008SBill Wendling       func_ptr f;
597*6f797008SBill Wendling       func_ptr g;
598*6f797008SBill Wendling     };
599*6f797008SBill Wendling   )c");
600*6f797008SBill Wendling 
601*6f797008SBill Wendling   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
602*6f797008SBill Wendling 
603*6f797008SBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
604*6f797008SBill Wendling 
605*6f797008SBill Wendling   EXPECT_TRUE(RD->isRandomized());
606*6f797008SBill Wendling }
607*6f797008SBill Wendling 
TEST(RANDSTRUCT_TEST,DisableAutoRandomizeStructOfFunctionPointers)608*6f797008SBill Wendling TEST(RANDSTRUCT_TEST, DisableAutoRandomizeStructOfFunctionPointers) {
609*6f797008SBill Wendling   const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
610*6f797008SBill Wendling     typedef void (*func_ptr)();
611*6f797008SBill Wendling 
612*6f797008SBill Wendling     struct test {
613*6f797008SBill Wendling       func_ptr a;
614*6f797008SBill Wendling       func_ptr b;
615*6f797008SBill Wendling       func_ptr c;
616*6f797008SBill Wendling       func_ptr d;
617*6f797008SBill Wendling       func_ptr e;
618*6f797008SBill Wendling       func_ptr f;
619*6f797008SBill Wendling       func_ptr g;
620*6f797008SBill Wendling     } __attribute__((no_randomize_layout));
621*6f797008SBill Wendling   )c");
622*6f797008SBill Wendling 
623*6f797008SBill Wendling   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
624*6f797008SBill Wendling 
625*6f797008SBill Wendling   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
626*6f797008SBill Wendling 
627*6f797008SBill Wendling   EXPECT_FALSE(RD->isRandomized());
628*6f797008SBill Wendling }
629*6f797008SBill Wendling 
6307aa8c38aSConnor Kuehl } // namespace ast_matchers
6317aa8c38aSConnor Kuehl } // namespace clang
632