danix800 created this revision.
danix800 added a project: clang.
Herald added subscribers: steakhal, manas, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
Herald added a reviewer: NoQ.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

This commit computes size of FAM which is normally allocated dynamically.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158499

Files:
  clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
  clang/test/Analysis/flexible-array-members.c

Index: clang/test/Analysis/flexible-array-members.c
===================================================================
--- clang/test/Analysis/flexible-array-members.c
+++ clang/test/Analysis/flexible-array-members.c
@@ -44,20 +44,52 @@
   clang_analyzer_dump(clang_analyzer_getExtent(&fam));
   clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
   // expected-warning@-2 {{4 S64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *p = (FAM *)alloca(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(p));
   clang_analyzer_dump(clang_analyzer_getExtent(p->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *q = (FAM *)malloc(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(q));
   clang_analyzer_dump(clang_analyzer_getExtent(q->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
   free(q);
+
+  q = (FAM *)malloc(sizeof(FAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(q));
+  clang_analyzer_dump(clang_analyzer_getExtent(q->data));
+  // expected-warning@-2 {{12 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(q);
+
+  typedef struct __attribute__((packed)) {
+    char c;
+    int data[];
+  } PackedFAM;
+
+  PackedFAM *t = (PackedFAM *)malloc(sizeof(PackedFAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(t));
+  clang_analyzer_dump(clang_analyzer_getExtent(t->data));
+  // expected-warning@-2 {{9 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(t);
+}
+
+void test_too_small_base(void) {
+  typedef struct FAM {
+    long c;
+    int data[0];
+  } FAM;
+  short s = 0;
+  FAM *p = (FAM *) &s;
+  clang_analyzer_dump(clang_analyzer_getExtent(p));
+  clang_analyzer_dump(clang_analyzer_getExtent(p->data));
+  // expected-warning@-2 {{2 S64b}}
+  // expected-warning@-2 {{Unknown}}
 }
 
 void test_zero_length_array_fam(void) {
Index: clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
@@ -25,6 +25,51 @@
 namespace clang {
 namespace ento {
 
+DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
+                                      const MemRegion *MR, SValBuilder &SVB);
+
+static bool isFlexibleArrayMember(const FieldDecl *FD) {
+  const auto *RD = FD->getParent();
+  if (!RD->hasFlexibleArrayMember())
+    return false;
+
+  const FieldDecl *LastFD = nullptr;
+  for (const FieldDecl *It : RD->fields())
+    LastFD = It;
+
+  return FD == LastFD;
+}
+
+static std::optional<DefinedOrUnknownSVal>
+getFlexibleArrayExtent(ProgramStateRef State, const MemRegion *MR,
+                       SValBuilder &SVB) {
+  const auto *FieldMR = dyn_cast<FieldRegion>(MR);
+  if (nullptr == FieldMR)
+    return std::nullopt;
+
+  const FieldDecl *FD = FieldMR->getDecl();
+  if (!isFlexibleArrayMember(FD))
+    return std::nullopt;
+
+  const RecordDecl *RD = FD->getParent();
+  const MemRegion *BaseMR = FieldMR->getBaseRegion();
+  auto BaseSize = getDynamicExtent(State, BaseMR, SVB);
+
+  auto &C = SVB.getContext();
+  uint64_t RecordSize = C.getTypeSizeInChars(C.getRecordType(RD)).getQuantity();
+  SVal RecordSizeVal = SVB.makeIntVal(RecordSize, C.getSizeType());
+
+  SVal BaseTooSmall =
+      SVB.evalBinOp(State, BO_LT, BaseSize, RecordSizeVal, C.BoolTy);
+  if (!BaseTooSmall.isUndef() &&
+      State->assume(*BaseTooSmall.getAs<DefinedOrUnknownSVal>(), true))
+    return std::nullopt;
+
+  SVal FlexibleArrayExtent =
+      SVB.evalBinOp(State, BO_Sub, BaseSize, RecordSizeVal, C.getSizeType());
+  return FlexibleArrayExtent.getAs<DefinedOrUnknownSVal>();
+}
+
 DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
                                       const MemRegion *MR, SValBuilder &SVB) {
   MR = MR->StripCasts();
@@ -32,6 +77,9 @@
   if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR))
     return *Size;
 
+  if (auto FlexibleArrayExtent = getFlexibleArrayExtent(State, MR, SVB))
+    return *FlexibleArrayExtent;
+
   return MR->getMemRegionManager().getStaticSize(MR, SVB);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to