void updated this revision to Diff 425593.
void marked 2 inline comments as done.
void added a comment.

Add a few more tests and remove a dead check.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123958/new/

https://reviews.llvm.org/D123958

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/Randstruct.h
  clang/lib/AST/Decl.cpp
  clang/lib/AST/Randstruct.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/test/Sema/init-randomized-struct.c
  clang/unittests/AST/RandstructTest.cpp

Index: clang/unittests/AST/RandstructTest.cpp
===================================================================
--- clang/unittests/AST/RandstructTest.cpp
+++ clang/unittests/AST/RandstructTest.cpp
@@ -132,6 +132,12 @@
 namespace clang {
 namespace ast_matchers {
 
+long declCount(const RecordDecl *RD) {
+  return llvm::count_if(RD->decls(), [&](const Decl *D) {
+    return isa<FieldDecl>(D) || isa<RecordDecl>(D);
+  });
+}
+
 #define RANDSTRUCT_TEST_SUITE_TEST RecordLayoutRandomizationTestSuiteTest
 
 TEST(RANDSTRUCT_TEST_SUITE_TEST, CanDetermineIfSubsequenceExists) {
@@ -159,9 +165,11 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_FALSE(RD->hasAttr<RandomizeLayoutAttr>());
   EXPECT_FALSE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
 TEST(RANDSTRUCT_TEST, MarkedNoRandomize) {
@@ -177,9 +185,11 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_TRUE(RD->hasAttr<NoRandomizeLayoutAttr>());
   EXPECT_FALSE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
 TEST(RANDSTRUCT_TEST, MarkedRandomize) {
@@ -195,9 +205,11 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_TRUE(RD->hasAttr<RandomizeLayoutAttr>());
   EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
 TEST(RANDSTRUCT_TEST, MismatchedAttrsDeclVsDef) {
@@ -280,19 +292,27 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
+
   const field_names Actual = getFieldNamesFromRecord(RD);
   const field_names Subseq = {"x", "y", "z"};
 
   EXPECT_TRUE(RD->isRandomized());
   EXPECT_TRUE(isSubsequence(Actual, Subseq));
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
-TEST(RANDSTRUCT_TEST, CheckVariableLengthArrayMemberRemainsAtEndOfStructure) {
+TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure1) {
   std::unique_ptr<ASTUnit> AST = makeAST(R"c(
     struct test {
         int a;
-        double b;
-        short c;
+        int b;
+        int c;
+        int d;
+        int e;
+        int f;
+        int g;
+        int h;
         char name[];
     } __attribute__((randomize_layout));
   )c");
@@ -300,8 +320,64 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
+  EXPECT_TRUE(RD->hasFlexibleArrayMember());
   EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
+  EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
+}
+
+TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure2) {
+  std::unique_ptr<ASTUnit> AST = makeAST(R"c(
+    struct test {
+        int a;
+        int b;
+        int c;
+        int d;
+        int e;
+        int f;
+        int g;
+        int h;
+        char name[0];
+    } __attribute__((randomize_layout));
+  )c");
+
+  EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+  const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
+
+  EXPECT_FALSE(RD->hasFlexibleArrayMember());
+  EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
+  EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
+}
+
+TEST(RANDSTRUCT_TEST, CheckFlexibleArrayMemberRemainsAtEndOfStructure3) {
+  std::unique_ptr<ASTUnit> AST = makeAST(R"c(
+    struct test {
+        int a;
+        int b;
+        int c;
+        int d;
+        int e;
+        int f;
+        int g;
+        int h;
+        char name[1];
+    } __attribute__((randomize_layout));
+  )c");
+
+  EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+  const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
+
+  EXPECT_FALSE(RD->hasFlexibleArrayMember());
+  EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
+  EXPECT_EQ(getFieldNamesFromRecord(RD).back(), "name");
 }
 
 TEST(RANDSTRUCT_TEST, RandstructDoesNotOverrideThePackedAttr) {
@@ -340,9 +416,11 @@
         getRecordDeclFromAST(AST->getASTContext(), "test_struct");
     const ASTRecordLayout *Layout =
         &AST->getASTContext().getASTRecordLayout(RD);
+    long OriginalDeclCount = declCount(RD);
 
     EXPECT_TRUE(RD->isRandomized());
     EXPECT_EQ(19, Layout->getSize().getQuantity());
+    EXPECT_EQ(OriginalDeclCount, declCount(RD));
   }
 
   {
@@ -350,9 +428,11 @@
         getRecordDeclFromAST(AST->getASTContext(), "another_struct");
     const ASTRecordLayout *Layout =
         &AST->getASTContext().getASTRecordLayout(RD);
+    long OriginalDeclCount = declCount(RD);
 
     EXPECT_TRUE(RD->isRandomized());
     EXPECT_EQ(10, Layout->getSize().getQuantity());
+    EXPECT_EQ(OriginalDeclCount, declCount(RD));
   }
 
   {
@@ -360,9 +440,11 @@
         getRecordDeclFromAST(AST->getASTContext(), "last_struct");
     const ASTRecordLayout *Layout =
         &AST->getASTContext().getASTRecordLayout(RD);
+    long OriginalDeclCount = declCount(RD);
 
     EXPECT_TRUE(RD->isRandomized());
     EXPECT_EQ(9, Layout->getSize().getQuantity());
+    EXPECT_EQ(OriginalDeclCount, declCount(RD));
   }
 }
 
@@ -378,8 +460,10 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
 TEST(RANDSTRUCT_TEST, RandstructDoesNotRandomizeUnionFieldOrder) {
@@ -396,10 +480,11 @@
 
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
-  const RecordDecl *RD =
-      getRecordDeclFromAST(AST->getASTContext(), "test");
+  const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_FALSE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 }
 
 TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsRetainFieldOrder) {
@@ -436,8 +521,10 @@
   EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
 
   const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
 
   EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
 
   bool AnonStructTested = false;
   bool AnonUnionTested = false;
@@ -467,5 +554,34 @@
   EXPECT_TRUE(AnonUnionTested);
 }
 
+TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsReferenced) {
+  std::unique_ptr<ASTUnit> AST = makeAST(R"c(
+    struct test {
+        int bacon;
+        long lettuce;
+        struct { double avocado; char blech; };
+        long long tomato;
+        union { char toast[8]; unsigned toast_thing; };
+        float mayonnaise;
+    } __attribute__((randomize_layout));
+
+    int foo(struct test *t) {
+      return t->blech;
+    }
+
+    char *bar(struct test *t) {
+      return t->toast;
+    }
+  )c");
+
+  EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+  const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");
+  long OriginalDeclCount = declCount(RD);
+
+  EXPECT_TRUE(RD->isRandomized());
+  EXPECT_EQ(OriginalDeclCount, declCount(RD));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: clang/test/Sema/init-randomized-struct.c
===================================================================
--- clang/test/Sema/init-randomized-struct.c
+++ clang/test/Sema/init-randomized-struct.c
@@ -55,3 +55,17 @@
 } __attribute__((randomize_layout));
 
 struct degen_test t11 = { foo }; // Okay
+
+struct static_assert_test {
+  int f;
+  _Static_assert(sizeof(int) == 4, "oh no!");
+} __attribute__((randomize_layout));
+
+struct static_assert_test t12 = { 42 }; // Okay
+
+struct enum_decl_test {
+  enum e { BORK = 42, FORK = 9 };
+  enum e f;
+} __attribute__((randomize_layout));
+
+struct enum_decl_test t12 = { enum_decl_test.BORK }; // Okay
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -2123,7 +2123,9 @@
   // worthwhile to skip over the rest of the initializer, though.
   RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
   RecordDecl::field_iterator FieldEnd = RD->field_end();
-  size_t NumRecordFields = std::distance(RD->field_begin(), RD->field_end());
+  size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
+    return isa<FieldDecl>(D) || isa<RecordDecl>(D);
+  });
   bool CheckForMissingFields =
     !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
   bool HasDesignatedInit = false;
@@ -2186,7 +2188,7 @@
     //   struct foo h = {bar};
     auto IsZeroInitializer = [&](const Expr *I) {
       if (IList->getNumInits() == 1) {
-        if (NumRecordFields == 1)
+        if (NumRecordDecls == 1)
           return true;
         if (const auto *IL = dyn_cast<IntegerLiteral>(I))
           return IL->getValue().isZero();
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -18057,16 +18057,14 @@
     // Handle attributes before checking the layout.
     ProcessDeclAttributeList(S, Record, Attrs);
 
-    // Maybe randomize the field order.
+    // Maybe randomize the record's decls.
     if (!getLangOpts().CPlusPlus && Record->hasAttr<RandomizeLayoutAttr>() &&
         !Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
         !Record->isRandomized()) {
-      SmallVector<Decl *, 32> OrigFieldOrdering(Record->fields());
-      SmallVector<Decl *, 32> NewFieldOrdering;
-      if (randstruct::randomizeStructureLayout(
-              Context, Record->getNameAsString(), OrigFieldOrdering,
-              NewFieldOrdering))
-        Record->reorderFields(NewFieldOrdering);
+      SmallVector<Decl *, 32> NewDeclOrdering;
+      if (randstruct::randomizeStructureLayout(Context, Record,
+                                               NewDeclOrdering))
+        Record->reorderDecls(NewDeclOrdering);
     }
 
     // We may have deferred checking for a deleted destructor. Check now.
Index: clang/lib/AST/Randstruct.cpp
===================================================================
--- clang/lib/AST/Randstruct.cpp
+++ clang/lib/AST/Randstruct.cpp
@@ -15,6 +15,8 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h" // For StaticAssertDecl
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/SmallVector.h"
 
@@ -170,16 +172,18 @@
 namespace clang {
 namespace randstruct {
 
-bool randomizeStructureLayout(const ASTContext &Context, StringRef Name,
-                              ArrayRef<Decl *> Fields,
+bool randomizeStructureLayout(const ASTContext &Context, RecordDecl *RD,
                               SmallVectorImpl<Decl *> &FinalOrdering) {
   SmallVector<FieldDecl *, 64> RandomizedFields;
+  SmallVector<Decl *, 8> PostRandomizedFields;
 
   unsigned TotalNumFields = 0;
-  for (Decl *D : Fields) {
+  for (Decl *D : RD->decls()) {
     ++TotalNumFields;
     if (auto *FD = dyn_cast<FieldDecl>(D))
       RandomizedFields.push_back(FD);
+    else if (isa<StaticAssertDecl>(D) || isa<IndirectFieldDecl>(D))
+      PostRandomizedFields.push_back(D);
     else
       FinalOrdering.push_back(D);
   }
@@ -187,33 +191,36 @@
   if (RandomizedFields.empty())
     return false;
 
-  // Struct might end with a variable-length array or an array of size 0 or 1,
+  // Struct might end with a flexible array or an array of size 0 or 1,
   // in which case we don't want to randomize it.
-  FieldDecl *VLA = nullptr;
-  const auto *CA =
-      dyn_cast<ConstantArrayType>(RandomizedFields.back()->getType());
-  if ((CA && (CA->getSize().sle(2) || CA->isIncompleteArrayType())) ||
-      llvm::any_of(Fields, [](Decl *D) {
-        if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
-          const Type *FDTy = FD->getType().getTypePtr();
-          if (const RecordType *FDTTy = FDTy->getAs<RecordType>())
-            return FDTTy->getDecl()->hasFlexibleArrayMember();
-        }
-        return false;
-      }))
-    VLA = RandomizedFields.pop_back_val();
+  FieldDecl *FlexibleArray =
+      RD->hasFlexibleArrayMember() ? RandomizedFields.pop_back_val() : nullptr;
+  if (!FlexibleArray) {
+    if (const auto *CA =
+            dyn_cast<ConstantArrayType>(RandomizedFields.back()->getType()))
+      if (CA->getSize().sle(2))
+        FlexibleArray = RandomizedFields.pop_back_val();
+  }
 
-  std::string Seed = (Context.getLangOpts().RandstructSeed + Name).str();
+  std::string Seed =
+      Context.getLangOpts().RandstructSeed + RD->getNameAsString();
   std::seed_seq SeedSeq(Seed.begin(), Seed.end());
   std::mt19937 RNG(SeedSeq);
 
   randomizeStructureLayoutImpl(Context, RandomizedFields, RNG);
-  if (VLA)
-    RandomizedFields.push_back(VLA);
 
+  // Plorp the randomized decls into the final ordering.
   FinalOrdering.insert(FinalOrdering.end(), RandomizedFields.begin(),
                        RandomizedFields.end());
 
+  // Add fields that belong towards the end of the RecordDecl.
+  FinalOrdering.insert(FinalOrdering.end(), PostRandomizedFields.begin(),
+                       PostRandomizedFields.end());
+
+  // Add back the flexible array.
+  if (FlexibleArray)
+    FinalOrdering.push_back(FlexibleArray);
+
   assert(TotalNumFields == FinalOrdering.size() &&
          "Decl count has been altered after Randstruct randomization!");
   (void)TotalNumFields;
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4705,8 +4705,8 @@
   return hasAttr<MSStructAttr>() || C.getLangOpts().MSBitfields == 1;
 }
 
-void RecordDecl::reorderFields(const SmallVectorImpl<Decl *> &Fields) {
-  std::tie(FirstDecl, LastDecl) = DeclContext::BuildDeclChain(Fields, false);
+void RecordDecl::reorderDecls(const SmallVectorImpl<Decl *> &Decls) {
+  std::tie(FirstDecl, LastDecl) = DeclContext::BuildDeclChain(Decls, false);
   LastDecl->NextInContextAndBits.setPointer(nullptr);
   setIsRandomized(true);
 }
Index: clang/include/clang/AST/Randstruct.h
===================================================================
--- clang/include/clang/AST/Randstruct.h
+++ clang/include/clang/AST/Randstruct.h
@@ -15,9 +15,7 @@
 #define LLVM_CLANG_AST_RANDSTRUCT_H
 
 namespace llvm {
-template <typename T> class ArrayRef;
 template <typename T> class SmallVectorImpl;
-class StringRef;
 } // end namespace llvm
 
 namespace clang {
@@ -28,8 +26,7 @@
 
 namespace randstruct {
 
-bool randomizeStructureLayout(const ASTContext &Context, llvm::StringRef Name,
-                              llvm::ArrayRef<Decl *> Fields,
+bool randomizeStructureLayout(const ASTContext &Context, RecordDecl *RD,
                               llvm::SmallVectorImpl<Decl *> &FinalOrdering);
 
 } // namespace randstruct
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -4072,7 +4072,7 @@
 
   void setIsRandomized(bool V) { RecordDeclBits.IsRandomized = V; }
 
-  void reorderFields(const SmallVectorImpl<Decl *> &Fields);
+  void reorderDecls(const SmallVectorImpl<Decl *> &Decls);
 
   /// Determines whether this declaration represents the
   /// injected class name.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to