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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits