Revert "[llvm] Improve llvm.objectsize computation by computing GEP, alloca and mallo...
[llvm-project.git] / clang / unittests / AST / RandstructTest.cpp
blobc22d866ed4fad07516c9737ad3faa8d5794aefa0
1 //===- unittest/AST/RandstructTest.cpp ------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains tests for Clang's structure field layout randomization.
11 //===----------------------------------------------------------------------===//
14 * Build this test suite by running `make ASTTests` in the build folder.
16 * Run this test suite by running the following in the build folder:
17 * ` ./tools/clang/unittests/AST/ASTTests
18 * --gtest_filter=RecordLayoutRandomization*`
21 #include "clang/AST/Randstruct.h"
22 #include "gtest/gtest.h"
24 #include "DeclMatcher.h"
25 #include "clang/AST/RecordLayout.h"
26 #include "clang/ASTMatchers/ASTMatchers.h"
27 #include "clang/Frontend/ASTUnit.h"
28 #include "clang/Testing/CommandLineArgs.h"
29 #include "clang/Tooling/Tooling.h"
30 #include "llvm/Support/ToolOutputFile.h"
32 #include <vector>
34 using namespace clang;
35 using namespace clang::ast_matchers;
36 using namespace clang::randstruct;
38 using field_names = std::vector<std::string>;
40 constexpr const char Seed[] = "1234567890abcdef";
42 static RecordDecl *getRecordDeclFromAST(const ASTContext &C,
43 const std::string &Name) {
44 RecordDecl *RD = FirstDeclMatcher<RecordDecl>().match(
45 C.getTranslationUnitDecl(), recordDecl(hasName(Name)));
46 return RD;
49 static std::vector<std::string> getFieldNamesFromRecord(const RecordDecl *RD) {
50 std::vector<std::string> Fields;
52 Fields.reserve(8);
53 for (auto *Field : RD->fields())
54 Fields.push_back(Field->getNameAsString());
56 return Fields;
59 static bool isSubsequence(const field_names &Seq, const field_names &Subseq) {
60 unsigned SeqLen = Seq.size();
61 unsigned SubLen = Subseq.size();
63 bool IsSubseq = false;
64 for (unsigned I = 0; I < SeqLen; ++I)
65 if (Seq[I] == Subseq[0]) {
66 IsSubseq = true;
67 for (unsigned J = 0; J + I < SeqLen && J < SubLen; ++J) {
68 if (Seq[J + I] != Subseq[J]) {
69 IsSubseq = false;
70 break;
75 return IsSubseq;
78 static bool recordsEqual(const std::unique_ptr<ASTUnit> &LHS,
79 const std::unique_ptr<ASTUnit> &RHS,
80 const std::string &RecordName) {
81 const RecordDecl *LHSRD =
82 getRecordDeclFromAST(LHS->getASTContext(), RecordName);
83 const RecordDecl *RHSRD =
84 getRecordDeclFromAST(LHS->getASTContext(), RecordName);
86 return getFieldNamesFromRecord(LHSRD) == getFieldNamesFromRecord(RHSRD);
89 static std::unique_ptr<ASTUnit>
90 makeAST(const std::string &SourceCode, bool ExpectError = false,
91 std::vector<std::string> RecordNames = std::vector<std::string>()) {
92 std::vector<std::string> Args = getCommandLineArgsForTesting(Lang_C99);
93 Args.push_back("-frandomize-layout-seed=" + std::string(Seed));
95 IgnoringDiagConsumer IgnoringConsumer = IgnoringDiagConsumer();
97 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs(
98 SourceCode, Args, "input.c", "clang-tool",
99 std::make_shared<PCHContainerOperations>(),
100 tooling::getClangStripDependencyFileAdjuster(),
101 tooling::FileContentMappings(), &IgnoringConsumer);
103 int SeedFileFD = -1;
104 llvm::SmallString<256> SeedFilename;
105 EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("seed", "rng", SeedFileFD,
106 SeedFilename));
107 llvm::ToolOutputFile SeedFile(SeedFilename, SeedFileFD);
108 SeedFile.os() << Seed << "\n";
110 Args.clear();
111 Args = getCommandLineArgsForTesting(Lang_C99);
112 Args.push_back("-frandomize-layout-seed-file=" +
113 SeedFile.getFilename().str());
115 std::unique_ptr<ASTUnit> ASTFileSeed = tooling::buildASTFromCodeWithArgs(
116 SourceCode, Args, "input.c", "clang-tool",
117 std::make_shared<PCHContainerOperations>(),
118 tooling::getClangStripDependencyFileAdjuster(),
119 tooling::FileContentMappings(), &IgnoringConsumer);
121 if (!ExpectError) {
122 if (RecordNames.empty())
123 RecordNames.push_back("test");
125 for (std::string Name : RecordNames)
126 EXPECT_TRUE(recordsEqual(AST, ASTFileSeed, Name));
129 return AST;
132 namespace clang {
133 namespace ast_matchers {
135 long declCount(const RecordDecl *RD) {
136 return llvm::count_if(RD->decls(), [&](const Decl *D) {
137 return isa<FieldDecl>(D) || isa<RecordDecl>(D);
141 #define RANDSTRUCT_TEST_SUITE_TEST RecordLayoutRandomizationTestSuiteTest
143 TEST(RANDSTRUCT_TEST_SUITE_TEST, CanDetermineIfSubsequenceExists) {
144 const field_names Seq = {"a", "b", "c", "d"};
146 EXPECT_TRUE(isSubsequence(Seq, {"b", "c"}));
147 EXPECT_TRUE(isSubsequence(Seq, {"a", "b", "c", "d"}));
148 EXPECT_TRUE(isSubsequence(Seq, {"b", "c", "d"}));
149 EXPECT_TRUE(isSubsequence(Seq, {"a"}));
150 EXPECT_FALSE(isSubsequence(Seq, {"a", "d"}));
153 #define RANDSTRUCT_TEST RecordLayoutRandomization
155 TEST(RANDSTRUCT_TEST, UnmarkedStruct) {
156 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
157 struct test {
158 int bacon;
159 long lettuce;
160 long long tomato;
161 float mayonnaise;
163 )c");
165 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
167 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
168 long OriginalDeclCount = declCount(RD);
170 EXPECT_FALSE(RD->hasAttr<RandomizeLayoutAttr>());
171 EXPECT_FALSE(RD->isRandomized());
172 EXPECT_EQ(OriginalDeclCount, declCount(RD));
175 TEST(RANDSTRUCT_TEST, MarkedNoRandomize) {
176 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
177 struct test {
178 int bacon;
179 long lettuce;
180 long long tomato;
181 float mayonnaise;
182 } __attribute__((no_randomize_layout));
183 )c");
185 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
187 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
188 long OriginalDeclCount = declCount(RD);
190 EXPECT_TRUE(RD->hasAttr<NoRandomizeLayoutAttr>());
191 EXPECT_FALSE(RD->isRandomized());
192 EXPECT_EQ(OriginalDeclCount, declCount(RD));
195 TEST(RANDSTRUCT_TEST, MarkedRandomize) {
196 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
197 struct test {
198 int bacon;
199 long lettuce;
200 long long tomato;
201 float mayonnaise;
202 } __attribute__((randomize_layout));
203 )c");
205 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
207 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
208 long OriginalDeclCount = declCount(RD);
210 EXPECT_TRUE(RD->hasAttr<RandomizeLayoutAttr>());
211 EXPECT_TRUE(RD->isRandomized());
212 EXPECT_EQ(OriginalDeclCount, declCount(RD));
215 TEST(RANDSTRUCT_TEST, MismatchedAttrsDeclVsDef) {
216 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
217 struct test __attribute__((randomize_layout));
218 struct test {
219 int bacon;
220 long lettuce;
221 long long tomato;
222 float mayonnaise;
223 } __attribute__((no_randomize_layout));
224 )c",
225 true);
227 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
229 const DiagnosticsEngine &Diags = AST->getDiagnostics();
231 EXPECT_FALSE(Diags.hasFatalErrorOccurred());
232 EXPECT_FALSE(Diags.hasUncompilableErrorOccurred());
233 EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
234 EXPECT_EQ(Diags.getNumWarnings(), 1u);
235 EXPECT_EQ(Diags.getNumErrors(), 0u);
238 TEST(RANDSTRUCT_TEST, MismatchedAttrsRandomizeVsNoRandomize) {
239 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
240 struct test {
241 int bacon;
242 long lettuce;
243 long long tomato;
244 float mayonnaise;
245 } __attribute__((randomize_layout)) __attribute__((no_randomize_layout));
246 )c",
247 true);
249 EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred());
251 const DiagnosticsEngine &Diags = AST->getDiagnostics();
253 EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
254 EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
255 EXPECT_EQ(Diags.getNumWarnings(), 0u);
256 EXPECT_EQ(Diags.getNumErrors(), 1u);
259 TEST(RANDSTRUCT_TEST, MismatchedAttrsNoRandomizeVsRandomize) {
260 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
261 struct test3 {
262 int bacon;
263 long lettuce;
264 long long tomato;
265 float mayonnaise;
266 } __attribute__((no_randomize_layout)) __attribute__((randomize_layout));
267 )c",
268 true);
270 EXPECT_TRUE(AST->getDiagnostics().hasErrorOccurred());
272 const DiagnosticsEngine &Diags = AST->getDiagnostics();
274 EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
275 EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
276 EXPECT_EQ(Diags.getNumWarnings(), 0u);
277 EXPECT_EQ(Diags.getNumErrors(), 1u);
280 TEST(RANDSTRUCT_TEST, CheckAdjacentBitfieldsRemainAdjacentAfterRandomization) {
281 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
282 struct test {
283 int a;
284 int b;
285 int x : 1;
286 int y : 1;
287 int z : 1;
288 int c;
289 } __attribute__((randomize_layout));
290 )c");
292 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
294 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
295 long OriginalDeclCount = declCount(RD);
297 const field_names Actual = getFieldNamesFromRecord(RD);
298 const field_names Subseq = {"x", "y", "z"};
300 EXPECT_TRUE(RD->isRandomized());
301 EXPECT_TRUE(isSubsequence(Actual, Subseq));
302 EXPECT_EQ(OriginalDeclCount, declCount(RD));
305 TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure1) {
306 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
307 struct test {
308 int a;
309 int b;
310 int c;
311 int d;
312 int e;
313 int f;
314 int g;
315 int h;
316 char name[];
317 } __attribute__((randomize_layout));
318 )c");
320 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
322 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
323 long OriginalDeclCount = declCount(RD);
325 EXPECT_TRUE(RD->hasFlexibleArrayMember());
326 EXPECT_TRUE(RD->isRandomized());
327 EXPECT_EQ(OriginalDeclCount, declCount(RD));
328 EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
331 TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure2) {
332 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
333 struct test {
334 int a;
335 int b;
336 int c;
337 int d;
338 int e;
339 int f;
340 int g;
341 int h;
342 char name[0];
343 } __attribute__((randomize_layout));
344 )c");
346 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
348 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
349 long OriginalDeclCount = declCount(RD);
351 EXPECT_FALSE(RD->hasFlexibleArrayMember());
352 EXPECT_TRUE(RD->isRandomized());
353 EXPECT_EQ(OriginalDeclCount, declCount(RD));
354 EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
357 TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure3) {
358 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
359 struct test {
360 int a;
361 int b;
362 int c;
363 int d;
364 int e;
365 int f;
366 int g;
367 int h;
368 char name[1];
369 } __attribute__((randomize_layout));
370 )c");
372 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
374 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
375 long OriginalDeclCount = declCount(RD);
377 EXPECT_FALSE(RD->hasFlexibleArrayMember());
378 EXPECT_TRUE(RD->isRandomized());
379 EXPECT_EQ(OriginalDeclCount, declCount(RD));
380 EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
383 TEST(RANDSTRUCT_TEST, RandstructDoesNotOverrideThePackedAttr) {
384 std::unique_ptr<ASTUnit> AST =
385 makeAST(R"c(
386 struct test_struct {
387 char a;
388 float b[3];
389 short c;
390 int d;
391 } __attribute__((packed, randomize_layout));
393 struct another_struct {
394 char a;
395 char b[5];
396 int c;
397 } __attribute__((packed, randomize_layout));
399 struct last_struct {
400 char a;
401 long long b;
402 int c[];
403 } __attribute__((packed, randomize_layout));
404 )c",
405 false,
406 std::vector<std::string>(
407 {"test_struct", "another_struct", "last_struct"}));
409 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
411 // FIXME (?): calling getASTRecordLayout is probably a necessary evil so that
412 // Clang's RecordBuilders can actually flesh out the information like
413 // alignment, etc.
415 const RecordDecl *RD =
416 getRecordDeclFromAST(AST->getASTContext(), "test_struct");
417 const ASTRecordLayout *Layout =
418 &AST->getASTContext().getASTRecordLayout(RD);
419 long OriginalDeclCount = declCount(RD);
421 EXPECT_TRUE(RD->isRandomized());
422 EXPECT_EQ(19, Layout->getSize().getQuantity());
423 EXPECT_EQ(OriginalDeclCount, declCount(RD));
427 const RecordDecl *RD =
428 getRecordDeclFromAST(AST->getASTContext(), "another_struct");
429 const ASTRecordLayout *Layout =
430 &AST->getASTContext().getASTRecordLayout(RD);
431 long OriginalDeclCount = declCount(RD);
433 EXPECT_TRUE(RD->isRandomized());
434 EXPECT_EQ(10, Layout->getSize().getQuantity());
435 EXPECT_EQ(OriginalDeclCount, declCount(RD));
439 const RecordDecl *RD =
440 getRecordDeclFromAST(AST->getASTContext(), "last_struct");
441 const ASTRecordLayout *Layout =
442 &AST->getASTContext().getASTRecordLayout(RD);
443 long OriginalDeclCount = declCount(RD);
445 EXPECT_TRUE(RD->isRandomized());
446 EXPECT_EQ(9, Layout->getSize().getQuantity());
447 EXPECT_EQ(OriginalDeclCount, declCount(RD));
451 TEST(RANDSTRUCT_TEST, ZeroWidthBitfieldsSeparateAllocationUnits) {
452 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
453 struct test {
454 int a : 1;
455 int : 0;
456 int b : 1;
457 } __attribute__((randomize_layout));
458 )c");
460 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
462 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
463 long OriginalDeclCount = declCount(RD);
465 EXPECT_TRUE(RD->isRandomized());
466 EXPECT_EQ(OriginalDeclCount, declCount(RD));
469 TEST(RANDSTRUCT_TEST, RandstructDoesNotRandomizeUnionFieldOrder) {
470 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
471 union test {
472 int a;
473 int b;
474 int c;
475 int d;
476 int e;
477 int f;
478 } __attribute__((randomize_layout));
479 )c");
481 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
483 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
484 long OriginalDeclCount = declCount(RD);
486 EXPECT_FALSE(RD->isRandomized());
487 EXPECT_EQ(OriginalDeclCount, declCount(RD));
490 TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) {
491 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
492 struct test {
493 int a;
494 struct sub_struct {
495 int b;
496 int c;
497 int d;
498 int e;
499 int f;
500 } __attribute__((randomize_layout)) s;
501 int f;
502 struct {
503 int g;
504 int h;
505 int i;
506 int j;
507 int k;
509 int l;
510 union {
511 int m;
512 int n;
513 int o;
514 int p;
515 int q;
517 int r;
518 } __attribute__((randomize_layout));
519 )c");
521 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
523 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
524 long OriginalDeclCount = declCount(RD);
526 EXPECT_TRUE(RD->isRandomized());
527 EXPECT_EQ(OriginalDeclCount, declCount(RD));
529 bool AnonStructTested = false;
530 bool AnonUnionTested = false;
532 for (const Decl *D : RD->decls())
533 if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
534 if (const auto *Record = FD->getType()->getAs<RecordType>()) {
535 RD = Record->getDecl();
536 if (RD->isAnonymousStructOrUnion()) {
537 // These field orders shouldn't change.
538 if (RD->isUnion()) {
539 const field_names Expected = {"m", "n", "o", "p", "q"};
541 EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));
542 AnonUnionTested = true;
543 } else {
544 const field_names Expected = {"g", "h", "i", "j", "k"};
546 EXPECT_EQ(Expected, getFieldNamesFromRecord(RD));
547 AnonStructTested = true;
553 EXPECT_TRUE(AnonStructTested);
554 EXPECT_TRUE(AnonUnionTested);
557 TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsReferenced) {
558 std::unique_ptr<ASTUnit> AST = makeAST(R"c(
559 struct test {
560 int bacon;
561 long lettuce;
562 struct { double avocado; char blech; };
563 long long tomato;
564 union { char toast[8]; unsigned toast_thing; };
565 float mayonnaise;
566 } __attribute__((randomize_layout));
568 int foo(struct test *t) {
569 return t->blech;
572 char *bar(struct test *t) {
573 return t->toast;
575 )c");
577 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
579 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
580 long OriginalDeclCount = declCount(RD);
582 EXPECT_TRUE(RD->isRandomized());
583 EXPECT_EQ(OriginalDeclCount, declCount(RD));
586 TEST(RANDSTRUCT_TEST, AutoRandomizeStructOfFunctionPointers) {
587 const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
588 typedef void (*func_ptr)();
590 struct test {
591 func_ptr a;
592 func_ptr b;
593 func_ptr c;
594 func_ptr d;
595 func_ptr e;
596 func_ptr f;
597 func_ptr g;
599 )c");
601 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
603 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
605 EXPECT_TRUE(RD->isRandomized());
608 TEST(RANDSTRUCT_TEST, DisableAutoRandomizeStructOfFunctionPointers) {
609 const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
610 typedef void (*func_ptr)();
612 struct test {
613 func_ptr a;
614 func_ptr b;
615 func_ptr c;
616 func_ptr d;
617 func_ptr e;
618 func_ptr f;
619 func_ptr g;
620 } __attribute__((no_randomize_layout));
621 )c");
623 EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
625 const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
627 EXPECT_FALSE(RD->isRandomized());
630 } // namespace ast_matchers
631 } // namespace clang