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