diff options
author | Gabor Marton <gabor.marton@ericsson.com> | 2020-04-02 16:59:02 +0200 |
---|---|---|
committer | Gabor Marton <gabor.marton@ericsson.com> | 2020-04-02 17:00:11 +0200 |
commit | 1525232e276153e325a49372894ae52ed07351a5 (patch) | |
tree | d7b7b2764288d9e116abe7fb5671fca09b08daad /clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | |
parent | da8eda1ab1ae97115f9ed170216ed89b69662578 (diff) | |
download | llvm-1525232e276153e325a49372894ae52ed07351a5.zip llvm-1525232e276153e325a49372894ae52ed07351a5.tar.gz llvm-1525232e276153e325a49372894ae52ed07351a5.tar.bz2 |
[analyzer] StdLibraryFunctionsChecker: fix bug with arg constraints
Summary:
Previously we induced a state split if there were multiple argument
constraints given for a function. This was because we called
`addTransition` inside the for loop.
The fix is to is to store the state and apply the next argument
constraint on that. And once the loop is finished we call `addTransition`.
Reviewers: NoQ, Szelethus, baloghadamsoftware
Subscribers: whisperity, xazax.hun, szepet, rnkovacs, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, gamesh411, C
Tags: #clang
Differential Revision: https://reviews.llvm.org/D76790
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 6e5f5f8..f03696d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -306,7 +306,11 @@ public: void checkPostCall(const CallEvent &Call, CheckerContext &C) const; bool evalCall(const CallEvent &Call, CheckerContext &C) const; - enum CheckKind { CK_StdCLibraryFunctionArgsChecker, CK_NumCheckKinds }; + enum CheckKind { + CK_StdCLibraryFunctionArgsChecker, + CK_StdCLibraryFunctionsTesterChecker, + CK_NumCheckKinds + }; DefaultBool ChecksEnabled[CK_NumCheckKinds]; CheckerNameRef CheckNames[CK_NumCheckKinds]; @@ -455,23 +459,26 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, const Summary &Summary = *FoundSummary; ProgramStateRef State = C.getState(); + ProgramStateRef NewState = State; for (const ValueConstraintPtr& VC : Summary.ArgConstraints) { - ProgramStateRef SuccessSt = VC->apply(State, Call, Summary); - ProgramStateRef FailureSt = VC->negate()->apply(State, Call, Summary); + ProgramStateRef SuccessSt = VC->apply(NewState, Call, Summary); + ProgramStateRef FailureSt = VC->negate()->apply(NewState, Call, Summary); // The argument constraint is not satisfied. if (FailureSt && !SuccessSt) { - if (ExplodedNode *N = C.generateErrorNode(State)) + if (ExplodedNode *N = C.generateErrorNode(NewState)) reportBug(Call, N, C); break; } else { - // Apply the constraint even if we cannot reason about the argument. This - // means both SuccessSt and FailureSt can be true. If we weren't applying - // the constraint that would mean that symbolic execution continues on a - // code whose behaviour is undefined. + // We will apply the constraint even if we cannot reason about the + // argument. This means both SuccessSt and FailureSt can be true. If we + // weren't applying the constraint that would mean that symbolic + // execution continues on a code whose behaviour is undefined. assert(SuccessSt); - C.addTransition(SuccessSt); + NewState = SuccessSt; } } + if (NewState && NewState != State) + C.addTransition(NewState); } void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, @@ -936,6 +943,32 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( {"getdelim", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), Getline(LongLongTy, LongLongMax)}}, }; + + // Functions for testing. + if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { + llvm::StringMap<Summaries> TestFunctionSummaryMap = { + {"__two_constrained_args", + Summaries{ + Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure) + .ArgConstraint( + ArgumentCondition(0U, WithinRange, SingleValue(1))) + .ArgConstraint( + ArgumentCondition(1U, WithinRange, SingleValue(1)))}}, + {"__arg_constrained_twice", + Summaries{Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .ArgConstraint( + ArgumentCondition(0U, OutOfRange, SingleValue(1))) + .ArgConstraint( + ArgumentCondition(0U, OutOfRange, SingleValue(2)))}}, + }; + for (auto &E : TestFunctionSummaryMap) { + auto InsertRes = + FunctionSummaryMap.insert({std::string(E.getKey()), E.getValue()}); + assert(InsertRes.second && + "Test functions must not clash with modeled functions"); + (void)InsertRes; + } + } } void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { @@ -958,3 +991,4 @@ bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) +REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) |