diff --git a/clang/unittests/AST/RandstructTest.cpp b/clang/unittests/AST/RandstructTest.cpp --- a/clang/unittests/AST/RandstructTest.cpp +++ b/clang/unittests/AST/RandstructTest.cpp @@ -27,6 +27,7 @@ #include "clang/Frontend/ASTUnit.h" #include "clang/Testing/CommandLineArgs.h" #include "clang/Tooling/Tooling.h" +#include "llvm/Support/ToolOutputFile.h" #include @@ -36,18 +37,7 @@ using field_names = std::vector; -static std::unique_ptr makeAST(const std::string &SourceCode) { - std::vector Args = getCommandLineArgsForTesting(Lang_C99); - Args.push_back("-frandomize-layout-seed=1234567890abcdef"); - - IgnoringDiagConsumer IgnoringConsumer = IgnoringDiagConsumer(); - - return tooling::buildASTFromCodeWithArgs( - SourceCode, Args, "input.c", "clang-tool", - std::make_shared(), - tooling::getClangStripDependencyFileAdjuster(), - tooling::FileContentMappings(), &IgnoringConsumer); -} +constexpr const char Seed[] = "1234567890abcdef"; static RecordDecl *getRecordDeclFromAST(const ASTContext &C, const std::string &Name) { @@ -85,10 +75,64 @@ return IsSubseq; } +static bool recordsEqual(const std::unique_ptr &LHS, + const std::unique_ptr &RHS, + const std::string &RecordName) { + const RecordDecl *LHSRD = + getRecordDeclFromAST(LHS->getASTContext(), RecordName); + const RecordDecl *RHSRD = + getRecordDeclFromAST(LHS->getASTContext(), RecordName); + + return getFieldNamesFromRecord(LHSRD) == getFieldNamesFromRecord(RHSRD); +} + +static std::unique_ptr +makeAST(const std::string &SourceCode, bool ExpectError = false, + std::vector RecordNames = std::vector()) { + std::vector Args = getCommandLineArgsForTesting(Lang_C99); + Args.push_back("-frandomize-layout-seed=" + std::string(Seed)); + + IgnoringDiagConsumer IgnoringConsumer = IgnoringDiagConsumer(); + + std::unique_ptr AST = tooling::buildASTFromCodeWithArgs( + SourceCode, Args, "input.c", "clang-tool", + std::make_shared(), + tooling::getClangStripDependencyFileAdjuster(), + tooling::FileContentMappings(), &IgnoringConsumer); + + int SeedFileFD = -1; + llvm::SmallString<256> SeedFilename; + EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("seed", "rng", SeedFileFD, + SeedFilename)); + llvm::ToolOutputFile SeedFile(SeedFilename, SeedFileFD); + SeedFile.os() << Seed << "\n"; + + Args.clear(); + Args = getCommandLineArgsForTesting(Lang_C99); + Args.push_back("-frandomize-layout-seed-file=" + + SeedFile.getFilename().str()); + + std::unique_ptr ASTFileSeed = tooling::buildASTFromCodeWithArgs( + SourceCode, Args, "input.c", "clang-tool", + std::make_shared(), + tooling::getClangStripDependencyFileAdjuster(), + tooling::FileContentMappings(), &IgnoringConsumer); + + if (!ExpectError) { + if (RecordNames.empty()) + RecordNames.push_back("test"); + + for (std::string Name : RecordNames) + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, Name)); + } + + return AST; +} + namespace clang { namespace ast_matchers { -#define RANDSTRUCT_TEST_SUITE_TEST StructureLayoutRandomizationTestSuiteTest +#define RANDSTRUCT_TEST_SUITE_TEST RecordLayoutRandomizationTestSuiteTest TEST(RANDSTRUCT_TEST_SUITE_TEST, CanDetermineIfSubsequenceExists) { const field_names Seq = {"a", "b", "c", "d"}; @@ -100,10 +144,10 @@ EXPECT_FALSE(isSubsequence(Seq, {"a", "d"})); } -#define RANDSTRUCT_TEST StructureLayoutRandomization +#define RANDSTRUCT_TEST RecordLayoutRandomization TEST(RANDSTRUCT_TEST, UnmarkedStruct) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int bacon; long lettuce; @@ -121,7 +165,7 @@ } TEST(RANDSTRUCT_TEST, MarkedNoRandomize) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int bacon; long lettuce; @@ -139,7 +183,7 @@ } TEST(RANDSTRUCT_TEST, MarkedRandomize) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int bacon; long lettuce; @@ -157,7 +201,7 @@ } TEST(RANDSTRUCT_TEST, MismatchedAttrsDeclVsDef) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test __attribute__((randomize_layout)); struct test { int bacon; @@ -165,11 +209,12 @@ long long tomato; float mayonnaise; } __attribute__((no_randomize_layout)); - )c"); + )c", + true); EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_FALSE(Diags.hasFatalErrorOccurred()); EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); @@ -179,18 +224,19 @@ } TEST(RANDSTRUCT_TEST, MismatchedAttrsRandomizeVsNoRandomize) { - const std::unique_ptr AST = makeAST(R"c( - struct test2 { + std::unique_ptr AST = makeAST(R"c( + struct test { int bacon; long lettuce; long long tomato; float mayonnaise; } __attribute__((randomize_layout)) __attribute__((no_randomize_layout)); - )c"); + )c", + true); EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_TRUE(Diags.hasUncompilableErrorOccurred()); EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred()); @@ -199,18 +245,19 @@ } TEST(RANDSTRUCT_TEST, MismatchedAttrsNoRandomizeVsRandomize) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test3 { int bacon; long lettuce; long long tomato; float mayonnaise; } __attribute__((no_randomize_layout)) __attribute__((randomize_layout)); - )c"); + )c", + true); EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_TRUE(Diags.hasUncompilableErrorOccurred()); EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred()); @@ -219,7 +266,7 @@ } TEST(RANDSTRUCT_TEST, CheckAdjacentBitfieldsRemainAdjacentAfterRandomization) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int a; int b; @@ -241,7 +288,7 @@ } TEST(RANDSTRUCT_TEST, CheckVariableLengthArrayMemberRemainsAtEndOfStructure) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int a; double b; @@ -258,7 +305,8 @@ } TEST(RANDSTRUCT_TEST, RandstructDoesNotOverrideThePackedAttr) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = + makeAST(R"c( struct test_struct { char a; float b[3]; @@ -277,7 +325,10 @@ long long b; int c[]; } __attribute__((packed, randomize_layout)); - )c"); + )c", + false, + std::vector( + {"test_struct", "another_struct", "last_struct"})); EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); @@ -316,7 +367,7 @@ } TEST(RANDSTRUCT_TEST, ZeroWidthBitfieldsSeparateAllocationUnits) { - const std::unique_ptr AST = makeAST(R"c( + std::unique_ptr AST = makeAST(R"c( struct test { int a : 1; int : 0; @@ -332,8 +383,8 @@ } TEST(RANDSTRUCT_TEST, RandstructDoesNotRandomizeUnionFieldOrder) { - const std::unique_ptr AST = makeAST(R"c( - union test_union { + std::unique_ptr AST = makeAST(R"c( + union test { int a; int b; int c; @@ -352,8 +403,8 @@ } TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) { - const std::unique_ptr AST = makeAST(R"c( - struct test_struct { + std::unique_ptr AST = makeAST(R"c( + struct test { int a; struct sub_struct { int b; @@ -384,8 +435,7 @@ EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); - const RecordDecl *RD = - getRecordDeclFromAST(AST->getASTContext(), "test_struct"); + const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); EXPECT_TRUE(RD->isRandomized());