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