[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
This commit is contained in:
Gabor Marton 2020-03-31 17:41:10 +02:00
parent 205085d4cc
commit 41928c97b6
2 changed files with 50 additions and 3 deletions

View File

@ -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<ArgNo> 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<DefinedOrUnknownSVal>())
@ -744,8 +761,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
IntRangeVector Ranges) {
return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
};
auto BufferSize = [](ArgNo BufArgN, ArgNo SizeArgN) {
return std::make_shared<BufferSizeConstraint>(BufArgN, SizeArgN);
auto BufferSize = [](auto... Args) {
return std::make_shared<BufferSizeConstraint>(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))));
}
}

View File

@ -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}}
}