From 41928c97b6a17264938fc765a6a0656d8b6e86ed Mon Sep 17 00:00:00 2001 From: Gabor Marton Date: Tue, 31 Mar 2020 17:41:10 +0200 Subject: [PATCH] [analyzer] ApiModeling: Add buffer size arg constraint with multiplier involved Summary: Further develop the buffer size argumentum constraint so it can handle sizes that we can get by multiplying two variables. Reviewers: Szelethus, NoQ, steakhal Subscribers: whisperity, xazax.hun, baloghadamsoftware, szepet, rnkovacs, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, gamesh411, Charusso, ASDenysPetrov, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D77148 --- .../Checkers/StdLibraryFunctionsChecker.cpp | 29 +++++++++++++++++-- .../std-c-library-functions-arg-constraints.c | 24 +++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index f661f29948b6..bd2f505849af 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -215,9 +215,16 @@ class StdLibraryFunctionsChecker // Represents a buffer argument with an additional size argument. // E.g. the first two arguments here: // ctime_s(char *buffer, rsize_t bufsz, const time_t *time); + // Another example: + // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); + // // Here, ptr is the buffer, and its minimum size is `size * nmemb`. class BufferSizeConstraint : public ValueConstraint { // The argument which holds the size of the buffer. ArgNo SizeArgN; + // The argument which is a multiplier to size. This is set in case of + // `fread` like functions where the size is computed as a multiplication of + // two arguments. + llvm::Optional SizeMultiplierArgN; // The operator we use in apply. This is negated in negate(). BinaryOperator::Opcode Op = BO_LE; @@ -225,17 +232,27 @@ class StdLibraryFunctionsChecker BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize) : ValueConstraint(Buffer), SizeArgN(BufSize) {} + BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier) + : ValueConstraint(Buffer), SizeArgN(BufSize), + SizeMultiplierArgN(BufSizeMultiplier) {} + ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, const Summary &Summary, CheckerContext &C) const override { + SValBuilder &SvalBuilder = C.getSValBuilder(); // The buffer argument. SVal BufV = getArgSVal(Call, getArgNo()); // The size argument. SVal SizeV = getArgSVal(Call, SizeArgN); + // Multiply with another argument if given. + if (SizeMultiplierArgN) { + SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN); + SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV, + Summary.getArgType(SizeArgN)); + } // The dynamic size of the buffer argument, got from the analyzer engine. SVal BufDynSize = getDynamicSizeWithOffset(State, BufV); - SValBuilder &SvalBuilder = C.getSValBuilder(); SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize, SvalBuilder.getContext().BoolTy); if (auto F = Feasible.getAs()) @@ -744,8 +761,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( IntRangeVector Ranges) { return std::make_shared(ArgN, Kind, Ranges); }; - auto BufferSize = [](ArgNo BufArgN, ArgNo SizeArgN) { - return std::make_shared(BufArgN, SizeArgN); + auto BufferSize = [](auto... Args) { + return std::make_shared(Args...); }; struct { auto operator()(RangeKind Kind, IntRangeVector Ranges) { @@ -988,6 +1005,12 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( EvalCallAsPure) .ArgConstraint( BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))); + addToFunctionSummaryMap( + "__buf_size_arg_constraint_mul", + Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}, + EvalCallAsPure) + .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1), + /*BufSizeMultiplier=*/ArgNo(2)))); } } 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 c59e4429f419..60338128ec89 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c @@ -149,3 +149,27 @@ void test_buf_size_symbolic_and_offset(int s) { // bugpath-note{{TRUE}} \ // bugpath-note{{'s' is <= 2}} } +int __buf_size_arg_constraint_mul(const void *, size_t, size_t); +void test_buf_size_concrete_with_multiplication() { + short buf[3]; // bugpath-note{{'buf' initialized here}} + __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \ + // 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_buf_size_symbolic_with_multiplication(size_t s) { + short buf[3]; + __buf_size_arg_constraint_mul(buf, s, sizeof(short)); + clang_analyzer_eval(s * sizeof(short) <= 6); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} +} +void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) { + short buf[3]; + __buf_size_arg_constraint_mul(buf + 1, s, sizeof(short)); + clang_analyzer_eval(s * sizeof(short) <= 4); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} +}