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,40 @@ using field_names = std::vector; -static std::unique_ptr makeAST(const std::string &SourceCode) { +static std::string Seed = "1234567890abcdef"; + +static auto makeAST = [](const std::string &SourceCode) { std::vector Args = getCommandLineArgsForTesting(Lang_C99); - Args.push_back("-frandomize-layout-seed=1234567890abcdef"); + Args.push_back("-frandomize-layout-seed=" + Seed); IgnoringDiagConsumer IgnoringConsumer = IgnoringDiagConsumer(); - return tooling::buildASTFromCodeWithArgs( + 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); + + return std::tuple(AST.release(), ASTFileSeed.release()); +}; static RecordDecl *getRecordDeclFromAST(const ASTContext &C, const std::string &Name) { @@ -85,6 +108,19 @@ return IsSubseq; } +static bool recordsEqual(const ASTUnit *LHS, const ASTUnit *RHS, + std::string RecordName) { + const RecordDecl *LHSRD = + getRecordDeclFromAST(LHS->getASTContext(), RecordName); + const RecordDecl *RHSRD = + getRecordDeclFromAST(LHS->getASTContext(), RecordName); + + std::vector LHSFields = getFieldNamesFromRecord(LHSRD); + std::vector RHSFields = getFieldNamesFromRecord(RHSRD); + + return LHSFields == RHSFields; +} + namespace clang { namespace ast_matchers { @@ -103,7 +139,8 @@ #define RANDSTRUCT_TEST StructureLayoutRandomization TEST(RANDSTRUCT_TEST, UnmarkedStruct) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int bacon; long lettuce; @@ -118,10 +155,13 @@ EXPECT_FALSE(RD->hasAttr()); EXPECT_FALSE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, MarkedNoRandomize) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int bacon; long lettuce; @@ -134,12 +174,16 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->hasAttr()); EXPECT_FALSE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, MarkedRandomize) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int bacon; long lettuce; @@ -152,12 +196,16 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->hasAttr()); EXPECT_TRUE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, MismatchedAttrsDeclVsDef) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test __attribute__((randomize_layout)); struct test { int bacon; @@ -169,18 +217,21 @@ EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_FALSE(Diags.hasFatalErrorOccurred()); EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred()); EXPECT_EQ(Diags.getNumWarnings(), 1u); EXPECT_EQ(Diags.getNumErrors(), 0u); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, MismatchedAttrsRandomizeVsNoRandomize) { - const std::unique_ptr AST = makeAST(R"c( - struct test2 { + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( + struct test { int bacon; long lettuce; long long tomato; @@ -190,16 +241,19 @@ EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_TRUE(Diags.hasUncompilableErrorOccurred()); EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred()); EXPECT_EQ(Diags.getNumWarnings(), 0u); EXPECT_EQ(Diags.getNumErrors(), 1u); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, MismatchedAttrsNoRandomizeVsRandomize) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test3 { int bacon; long lettuce; @@ -210,16 +264,19 @@ EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred()); - DiagnosticsEngine &Diags = AST->getDiagnostics(); + const DiagnosticsEngine &Diags = AST->getDiagnostics(); EXPECT_TRUE(Diags.hasUncompilableErrorOccurred()); EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred()); EXPECT_EQ(Diags.getNumWarnings(), 0u); EXPECT_EQ(Diags.getNumErrors(), 1u); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, CheckAdjacentBitfieldsRemainAdjacentAfterRandomization) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int a; int b; @@ -236,12 +293,16 @@ const field_names Actual = getFieldNamesFromRecord(RD); const field_names Subseq = {"x", "y", "z"}; + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->isRandomized()); EXPECT_TRUE(isSubsequence(Actual, Subseq)); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, CheckVariableLengthArrayMemberRemainsAtEndOfStructure) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int a; double b; @@ -254,11 +315,15 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, RandstructDoesNotOverrideThePackedAttr) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test_struct { char a; float b[3]; @@ -290,6 +355,7 @@ const ASTRecordLayout *Layout = &AST->getASTContext().getASTRecordLayout(RD); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test_struct")); EXPECT_TRUE(RD->isRandomized()); EXPECT_EQ(19, Layout->getSize().getQuantity()); } @@ -300,6 +366,7 @@ const ASTRecordLayout *Layout = &AST->getASTContext().getASTRecordLayout(RD); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "another_struct")); EXPECT_TRUE(RD->isRandomized()); EXPECT_EQ(10, Layout->getSize().getQuantity()); } @@ -310,13 +377,18 @@ const ASTRecordLayout *Layout = &AST->getASTContext().getASTRecordLayout(RD); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "last_struct")); EXPECT_TRUE(RD->isRandomized()); EXPECT_EQ(9, Layout->getSize().getQuantity()); } + + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, ZeroWidthBitfieldsSeparateAllocationUnits) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test { int a : 1; int : 0; @@ -328,11 +400,15 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, RandstructDoesNotRandomizeUnionFieldOrder) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( union test_union { int a; int b; @@ -348,11 +424,15 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test_union"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test_union")); EXPECT_FALSE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( struct test_struct { int a; struct sub_struct { @@ -387,6 +467,7 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test_struct"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test_struct")); EXPECT_TRUE(RD->isRandomized()); bool AnonStructTested = false; @@ -415,10 +496,13 @@ EXPECT_TRUE(AnonStructTested); EXPECT_TRUE(AnonUnionTested); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, AutoRandomizeStructOfFunctionPointers) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( typedef void (*func_ptr)(); struct test { @@ -436,11 +520,15 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_TRUE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } TEST(RANDSTRUCT_TEST, DisableAutoRandomizeStructOfFunctionPointers) { - const std::unique_ptr AST = makeAST(R"c( + const ASTUnit *AST, *ASTFileSeed; + std::tie(AST, ASTFileSeed) = makeAST(R"c( typedef void (*func_ptr)(); struct test { @@ -458,7 +546,10 @@ const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test"); + EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, "test")); EXPECT_FALSE(RD->isRandomized()); + delete AST; + delete ASTFileSeed; } } // namespace ast_matchers