Author: Gabor Marton Date: 2020-03-20T17:34:29+01:00 New Revision: ededa65d559dac04ae50d3a33610875bb8f1a85e
URL: https://github.com/llvm/llvm-project/commit/ededa65d559dac04ae50d3a33610875bb8f1a85e DIFF: https://github.com/llvm/llvm-project/commit/ededa65d559dac04ae50d3a33610875bb8f1a85e.diff LOG: [analyzer] StdLibraryFunctionsChecker: Add NotNull Arg Constraint Reviewers: NoQ, Szelethus, balazske, gamesh411, baloghadamsoftware, steakhal Subscribers: whisperity, xazax.hun, szepet, rnkovacs, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, Charusso, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D75063 Added: Modified: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp clang/test/Analysis/std-c-library-functions-arg-constraints.c clang/test/Analysis/std-c-library-functions.c Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 2e956cc2bfe7..590dc8b67690 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -183,6 +183,29 @@ class StdLibraryFunctionsChecker const Summary &Summary) const override; }; + class NotNullConstraint : public ValueConstraint { + using ValueConstraint::ValueConstraint; + // This variable has a role when we negate the constraint. + bool CannotBeNull = true; + + public: + ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, + const Summary &Summary) const override { + SVal V = getArgSVal(Call, getArgNo()); + DefinedOrUnknownSVal L = V.castAs<DefinedOrUnknownSVal>(); + if (!L.getAs<Loc>()) + return State; + + return State->assume(L, CannotBeNull); + } + + ValueConstraintPtr negate() const override { + NotNullConstraint Tmp(*this); + Tmp.CannotBeNull = !this->CannotBeNull; + return std::make_shared<NotNullConstraint>(Tmp); + } + }; + /// The complete list of constraints that defines a single branch. typedef std::vector<ValueConstraintPtr> ConstraintSet; @@ -233,9 +256,6 @@ class StdLibraryFunctionsChecker "We should have had no significant void types in the spec"); assert(T.isCanonical() && "We should only have canonical types in the spec"); - // FIXME: lift this assert (but not the ones above!) - assert(T->isIntegralOrEnumerationType() && - "We only support integral ranges in the spec"); } public: @@ -602,6 +622,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( const QualType LongTy = ACtx.LongTy; const QualType LongLongTy = ACtx.LongLongTy; const QualType SizeTy = ACtx.getSizeType(); + const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *T + const QualType ConstVoidPtrTy = + ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *T const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); @@ -672,6 +695,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}}; }; auto LessThanOrEq = BO_LE; + auto NotNull = [&](ArgNo ArgN) { + return std::make_shared<NotNullConstraint>(ArgN); + }; using RetType = QualType; // Templates for summaries that are reused by many functions. @@ -687,11 +713,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( ReturnValueCondition(WithinRange, Range(-1, Max))}); }; auto Fread = [&]() { - return Summary(ArgTypes{Irrelevant, Irrelevant, SizeTy, Irrelevant}, + return Summary(ArgTypes{VoidPtrTy, Irrelevant, SizeTy, Irrelevant}, + RetType{SizeTy}, NoEvalCall) + .Case({ + ReturnValueCondition(LessThanOrEq, ArgNo(2)), + }) + .ArgConstraint(NotNull(ArgNo(0))); + }; + auto Fwrite = [&]() { + return Summary(ArgTypes{ConstVoidPtrTy, Irrelevant, SizeTy, Irrelevant}, RetType{SizeTy}, NoEvalCall) .Case({ ReturnValueCondition(LessThanOrEq, ArgNo(2)), - }); + }) + .ArgConstraint(NotNull(ArgNo(0))); }; auto Getline = [&](RetType R, RangeInt Max) { return Summary(ArgTypes{Irrelevant, Irrelevant, Irrelevant}, RetType{R}, @@ -893,7 +928,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( {"write", Summaries{Read(IntTy, IntMax), Read(LongTy, LongMax), Read(LongLongTy, LongLongMax)}}, {"fread", Summaries{Fread()}}, - {"fwrite", Summaries{Fread()}}, + {"fwrite", Summaries{Fwrite()}}, // getline()-like functions either fail or read at least the delimiter. {"getline", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), Getline(LongLongTy, LongLongMax)}}, diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c index 07a9df9526fc..a20b90ad1ccb 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c @@ -59,3 +59,29 @@ void test_alnum_symbolic2(int x) { (void)ret; } } + +typedef struct FILE FILE; +typedef typeof(sizeof(int)) size_t; +size_t fread(void *, size_t, size_t, FILE *); +void test_notnull_concrete(FILE *fp) { + fread(0, sizeof(int), 10, fp); // \ + // report-warning{{Function argument constraint is not satisfied}} \ + // bugpath-warning{{Function argument constraint is not satisfied}} \ + // bugpath-note{{Function argument constraint is not satisfied}} +} +void test_notnull_symbolic(FILE *fp, int *buf) { + fread(buf, sizeof(int), 10, fp); + clang_analyzer_eval(buf != 0); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} \ + // bugpath-note{{'buf' is not equal to null}} +} +void test_notnull_symbolic2(FILE *fp, int *buf) { + if (!buf) // bugpath-note{{Assuming 'buf' is null}} \ + // bugpath-note{{Taking true branch}} + fread(buf, sizeof(int), 10, fp); // \ + // report-warning{{Function argument constraint is not satisfied}} \ + // bugpath-warning{{Function argument constraint is not satisfied}} \ + // bugpath-note{{Function argument constraint is not satisfied}} +} diff --git a/clang/test/Analysis/std-c-library-functions.c b/clang/test/Analysis/std-c-library-functions.c index 2a090f397714..3f700a7c39a4 100644 --- a/clang/test/Analysis/std-c-library-functions.c +++ b/clang/test/Analysis/std-c-library-functions.c @@ -78,10 +78,13 @@ void test_read_write(int fd, char *buf) { size_t fread(void *, size_t, size_t, FILE *); size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict); void test_fread_fwrite(FILE *fp, int *buf) { + size_t x = fwrite(buf, sizeof(int), 10, fp); clang_analyzer_eval(x <= 10); // expected-warning{{TRUE}} + size_t y = fread(buf, sizeof(int), 10, fp); clang_analyzer_eval(y <= 10); // expected-warning{{TRUE}} + size_t z = fwrite(buf, sizeof(int), y, fp); clang_analyzer_eval(z <= y); // expected-warning{{TRUE}} } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits