[analyzer] Fix calculating offset for fields with an empty type
authorGeorgy Komarov <jubnzv@gmail.com>
Fri, 28 May 2021 08:58:50 +0000 (11:58 +0300)
committerGeorgy Komarov <jubnzv@gmail.com>
Sun, 4 Jul 2021 03:57:11 +0000 (06:57 +0300)
Fix offset calculation routines in padding checker to avoid assertion
errors described in bugzilla issue 50426. The fields that are subojbects
of zero size, marked with [[no_unique_address]] or empty bitfields will
be excluded from padding calculation routines.

Reviewed By: NoQ

Differential Revision: https://reviews.llvm.org/D104097

clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
clang/test/Analysis/padding_no_unique_address.cpp [new file with mode: 0644]

index 96f0d9b..40472cc 100644 (file)
@@ -193,6 +193,11 @@ public:
     CharUnits PaddingSum;
     CharUnits Offset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
     for (const FieldDecl *FD : RD->fields()) {
+      // Skip field that is a subobject of zero size, marked with
+      // [[no_unique_address]] or an empty bitfield, because its address can be
+      // set the same as the other fields addresses.
+      if (FD->isZeroSize(ASTContext))
+        continue;
       // This checker only cares about the padded size of the
       // field, and not the data size. If the field is a record
       // with tail padding, then we won't put that number in our
@@ -249,7 +254,7 @@ public:
       RetVal.Field = FD;
       auto &Ctx = FD->getASTContext();
       auto Info = Ctx.getTypeInfoInChars(FD->getType());
-      RetVal.Size = Info.Width;
+      RetVal.Size = FD->isZeroSize(Ctx) ? CharUnits::Zero() : Info.Width;
       RetVal.Align = Info.Align;
       assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity()));
       if (auto Max = FD->getMaxAlignment())
diff --git a/clang/test/Analysis/padding_no_unique_address.cpp b/clang/test/Analysis/padding_no_unique_address.cpp
new file mode 100644 (file)
index 0000000..4f26922
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-linux-gnu -analyzer-checker=optin.performance -analyzer-config optin.performance.Padding:AllowedPad=2 -verify %s
+
+class Empty {}; // no-warning
+
+// expected-warning@+1{{Excessive padding in 'struct NoUniqueAddressWarn1' (6 padding}}
+struct NoUniqueAddressWarn1 {
+  char c1;
+  [[no_unique_address]] Empty empty;
+  int i;
+  char c2;
+};
+
+// expected-warning@+1{{Excessive padding in 'struct NoUniqueAddressWarn2' (6 padding}}
+struct NoUniqueAddressWarn2 {
+    char c1;
+    [[no_unique_address]] Empty e1, e2;
+    int i;
+    char c2;
+};
+
+struct NoUniqueAddressNoWarn1 {
+  char c1;
+  [[no_unique_address]] Empty empty;
+  char c2;
+};
+
+struct NoUniqueAddressNoWarn2 {
+  char c1;
+  [[no_unique_address]] Empty e1, e2;
+};