Skip to content

Commit 4482063

Browse files
committed
[analyzer] NFC: Change evalCall() to provide a CallEvent.
This changes the checker callback signature to use the modern, easy to use interface. Additionally, this unblocks future work on allowing checkers to implement evalCall() for calls that don't correspond to any call-expression or require additional information that's only available as part of the CallEvent, such as C++ constructors and destructors. Differential Revision: https://reviews.llvm.org/D62440 llvm-svn: 363893
1 parent 3707b05 commit 4482063

12 files changed

+96
-87
lines changed

clang/include/clang/StaticAnalyzer/Core/Checker.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,9 @@ class Assume {
474474

475475
class Call {
476476
template <typename CHECKER>
477-
static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) {
478-
return ((const CHECKER *)checker)->evalCall(CE, C);
477+
static bool _evalCall(void *checker, const CallEvent &Call,
478+
CheckerContext &C) {
479+
return ((const CHECKER *)checker)->evalCall(Call, C);
479480
}
480481

481482
public:

clang/include/clang/StaticAnalyzer/Core/CheckerManager.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ class CheckerManager {
490490
CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond,
491491
bool assumption)>;
492492

493-
using EvalCallFunc = CheckerFn<bool (const CallExpr *, CheckerContext &)>;
493+
using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>;
494494

495495
using CheckEndOfTranslationUnit =
496496
CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &,

clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp

+18-13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/Basic/Builtins.h"
1515
#include "clang/StaticAnalyzer/Core/Checker.h"
1616
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
17+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
1718
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1819

1920
using namespace clang;
@@ -23,30 +24,32 @@ namespace {
2324

2425
class BuiltinFunctionChecker : public Checker<eval::Call> {
2526
public:
26-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
27+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
2728
};
2829

2930
}
3031

31-
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
32+
bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
3233
CheckerContext &C) const {
3334
ProgramStateRef state = C.getState();
34-
const FunctionDecl *FD = C.getCalleeDecl(CE);
35-
const LocationContext *LCtx = C.getLocationContext();
35+
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
3636
if (!FD)
3737
return false;
3838

39+
const LocationContext *LCtx = C.getLocationContext();
40+
const Expr *CE = Call.getOriginExpr();
41+
3942
switch (FD->getBuiltinID()) {
4043
default:
4144
return false;
4245

4346
case Builtin::BI__builtin_assume: {
44-
assert (CE->arg_begin() != CE->arg_end());
45-
SVal ArgSVal = C.getSVal(CE->getArg(0));
46-
if (ArgSVal.isUndef())
47+
assert (Call.getNumArgs() > 0);
48+
SVal Arg = Call.getArgSVal(0);
49+
if (Arg.isUndef())
4750
return true; // Return true to model purity.
4851

49-
state = state->assume(ArgSVal.castAs<DefinedOrUnknownSVal>(), true);
52+
state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true);
5053
// FIXME: do we want to warn here? Not right now. The most reports might
5154
// come from infeasible paths, thus being false positives.
5255
if (!state) {
@@ -66,9 +69,9 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
6669
// __builtin_assume_aligned, just return the value of the subexpression.
6770
// __builtin_addressof is going from a reference to a pointer, but those
6871
// are represented the same way in the analyzer.
69-
assert (CE->arg_begin() != CE->arg_end());
70-
SVal X = C.getSVal(*(CE->arg_begin()));
71-
C.addTransition(state->BindExpr(CE, LCtx, X));
72+
assert (Call.getNumArgs() > 0);
73+
SVal Arg = Call.getArgSVal(0);
74+
C.addTransition(state->BindExpr(CE, LCtx, Arg));
7275
return true;
7376
}
7477

@@ -82,12 +85,14 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
8285
// Set the extent of the region in bytes. This enables us to use the
8386
// SVal of the argument directly. If we save the extent in bits, we
8487
// cannot represent values like symbol*8.
85-
auto Size = C.getSVal(*(CE->arg_begin())).castAs<DefinedOrUnknownSVal>();
88+
auto Size = Call.getArgSVal(0);
89+
if (Size.isUndef())
90+
return true; // Return true to model purity.
8691

8792
SValBuilder& svalBuilder = C.getSValBuilder();
8893
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
8994
DefinedOrUnknownSVal extentMatchesSizeArg =
90-
svalBuilder.evalEQ(state, Extent, Size);
95+
svalBuilder.evalEQ(state, Extent, Size.castAs<DefinedOrUnknownSVal>());
9196
state = state->assume(extentMatchesSizeArg, true);
9297
assert(state && "The region should not have any previous constraints");
9398

clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1818
#include "clang/StaticAnalyzer/Core/Checker.h"
1919
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
20+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
2021
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2122
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
2223
#include "llvm/ADT/STLExtras.h"
@@ -57,7 +58,7 @@ class CStringChecker : public Checker< eval::Call,
5758

5859
static void *getTag() { static int tag; return &tag; }
5960

60-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
61+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
6162
void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
6263
void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const;
6364
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
@@ -2334,8 +2335,8 @@ static CStringChecker::FnCheck identifyCall(const CallExpr *CE,
23342335
return nullptr;
23352336
}
23362337

2337-
bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
2338-
2338+
bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
2339+
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
23392340
FnCheck evalFunction = identifyCall(CE, C);
23402341

23412342
// If the callee isn't a string function, let another checker handle it.

clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp

+20-37
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1515
#include "clang/StaticAnalyzer/Core/Checker.h"
1616
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
17+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
1718
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1819
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
1920
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -37,53 +38,44 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
3738
// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
3839
// | |
3940
// bug<--foo()-- JAIL_ENTERED<--foo()--
40-
class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > {
41-
mutable IdentifierInfo *II_chroot, *II_chdir;
41+
class ChrootChecker : public Checker<eval::Call, check::PreCall> {
4242
// This bug refers to possibly break out of a chroot() jail.
4343
mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
4444

45+
const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
46+
4547
public:
46-
ChrootChecker() : II_chroot(nullptr), II_chdir(nullptr) {}
48+
ChrootChecker() {}
4749

4850
static void *getTag() {
4951
static int x;
5052
return &x;
5153
}
5254

53-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
54-
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
55+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
56+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
5557

5658
private:
57-
void Chroot(CheckerContext &C, const CallExpr *CE) const;
58-
void Chdir(CheckerContext &C, const CallExpr *CE) const;
59+
void evalChroot(const CallEvent &Call, CheckerContext &C) const;
60+
void evalChdir(const CallEvent &Call, CheckerContext &C) const;
5961
};
6062

6163
} // end anonymous namespace
6264

63-
bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
64-
const FunctionDecl *FD = C.getCalleeDecl(CE);
65-
if (!FD)
66-
return false;
67-
68-
ASTContext &Ctx = C.getASTContext();
69-
if (!II_chroot)
70-
II_chroot = &Ctx.Idents.get("chroot");
71-
if (!II_chdir)
72-
II_chdir = &Ctx.Idents.get("chdir");
73-
74-
if (FD->getIdentifier() == II_chroot) {
75-
Chroot(C, CE);
65+
bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
66+
if (Call.isCalled(Chroot)) {
67+
evalChroot(Call, C);
7668
return true;
7769
}
78-
if (FD->getIdentifier() == II_chdir) {
79-
Chdir(C, CE);
70+
if (Call.isCalled(Chdir)) {
71+
evalChdir(Call, C);
8072
return true;
8173
}
8274

8375
return false;
8476
}
8577

86-
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
78+
void ChrootChecker::evalChroot(const CallEvent &Call, CheckerContext &C) const {
8779
ProgramStateRef state = C.getState();
8880
ProgramStateManager &Mgr = state->getStateManager();
8981

@@ -93,7 +85,7 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
9385
C.addTransition(state);
9486
}
9587

96-
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
88+
void ChrootChecker::evalChdir(const CallEvent &Call, CheckerContext &C) const {
9789
ProgramStateRef state = C.getState();
9890
ProgramStateManager &Mgr = state->getStateManager();
9991

@@ -103,7 +95,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
10395
return;
10496

10597
// After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
106-
const Expr *ArgExpr = CE->getArg(0);
98+
const Expr *ArgExpr = Call.getArgExpr(0);
10799
SVal ArgVal = C.getSVal(ArgExpr);
108100

109101
if (const MemRegion *R = ArgVal.getAsRegion()) {
@@ -120,19 +112,10 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
120112
}
121113

122114
// Check the jail state before any function call except chroot and chdir().
123-
void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
124-
const FunctionDecl *FD = C.getCalleeDecl(CE);
125-
if (!FD)
126-
return;
127-
128-
ASTContext &Ctx = C.getASTContext();
129-
if (!II_chroot)
130-
II_chroot = &Ctx.Idents.get("chroot");
131-
if (!II_chdir)
132-
II_chdir = &Ctx.Idents.get("chdir");
133-
115+
void ChrootChecker::checkPreCall(const CallEvent &Call,
116+
CheckerContext &C) const {
134117
// Ignore chroot and chdir.
135-
if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
118+
if (Call.isCalled(Chroot) || Call.isCalled(Chdir))
136119
return;
137120

138121
// If jail state is ROOT_CHANGED, generate BugReport.

clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1212
#include "clang/StaticAnalyzer/Core/Checker.h"
1313
#include "clang/StaticAnalyzer/Core/IssueHash.h"
14+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
1415
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1516
#include "llvm/ADT/StringSwitch.h"
1617
#include "llvm/Support/ScopedPrinter.h"
@@ -53,7 +54,7 @@ class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols,
5354
ExplodedNode *N) const;
5455

5556
public:
56-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
57+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
5758
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
5859
void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
5960
ExprEngine &Eng) const;
@@ -63,8 +64,12 @@ class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols,
6364
REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
6465
REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *)
6566

66-
bool ExprInspectionChecker::evalCall(const CallExpr *CE,
67+
bool ExprInspectionChecker::evalCall(const CallEvent &Call,
6768
CheckerContext &C) const {
69+
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
70+
if (!CE)
71+
return false;
72+
6873
// These checks should have no effect on the surrounding environment
6974
// (globals should not be invalidated, etc), hence the use of evalCall.
7075
FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -886,14 +886,19 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
886886
// Handle the return values of retain-count-related functions.
887887
//===----------------------------------------------------------------------===//
888888

889-
bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
889+
bool RetainCountChecker::evalCall(const CallEvent &Call,
890+
CheckerContext &C) const {
890891
ProgramStateRef state = C.getState();
891-
const FunctionDecl *FD = C.getCalleeDecl(CE);
892+
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
892893
if (!FD)
893894
return false;
894895

896+
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
897+
if (!CE)
898+
return false;
899+
895900
RetainSummaryManager &SmrMgr = getSummaryManager(C);
896-
QualType ResultTy = CE->getCallReturnType(C.getASTContext());
901+
QualType ResultTy = Call.getResultType();
897902

898903
// See if the function has 'rc_ownership_trusted_implementation'
899904
// annotate attribute. If it does, we will not inline it.

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ class RetainCountChecker
310310
const CallEvent &Call,
311311
CheckerContext &C) const;
312312

313-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
313+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
314314

315315
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
316316
bool Assumption) const;

clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp

+11-13
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,30 @@ using namespace ento;
2626

2727
namespace {
2828
class SmartPtrModeling : public Checker<eval::Call> {
29-
bool isNullAfterMoveMethod(const CXXInstanceCall *Call) const;
29+
bool isNullAfterMoveMethod(const CallEvent &Call) const;
3030

3131
public:
32-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
32+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
3333
};
3434
} // end of anonymous namespace
3535

36-
bool SmartPtrModeling::isNullAfterMoveMethod(
37-
const CXXInstanceCall *Call) const {
36+
bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
3837
// TODO: Update CallDescription to support anonymous calls?
3938
// TODO: Handle other methods, such as .get() or .release().
4039
// But once we do, we'd need a visitor to explain null dereferences
4140
// that are found via such modeling.
42-
const auto *CD = dyn_cast_or_null<CXXConversionDecl>(Call->getDecl());
41+
const auto *CD = dyn_cast_or_null<CXXConversionDecl>(Call.getDecl());
4342
return CD && CD->getConversionType()->isBooleanType();
4443
}
4544

46-
bool SmartPtrModeling::evalCall(const CallExpr *CE, CheckerContext &C) const {
47-
CallEventRef<> CallRef = C.getStateManager().getCallEventManager().getCall(
48-
CE, C.getState(), C.getLocationContext());
49-
const auto *Call = dyn_cast_or_null<CXXInstanceCall>(CallRef);
50-
if (!Call || !isNullAfterMoveMethod(Call))
45+
bool SmartPtrModeling::evalCall(const CallEvent &Call,
46+
CheckerContext &C) const {
47+
if (!isNullAfterMoveMethod(Call))
5148
return false;
5249

5350
ProgramStateRef State = C.getState();
54-
const MemRegion *ThisR = Call->getCXXThisVal().getAsRegion();
51+
const MemRegion *ThisR =
52+
cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
5553

5654
if (!move::isMovedFrom(State, ThisR)) {
5755
// TODO: Model this case as well. At least, avoid invalidation of globals.
@@ -60,8 +58,8 @@ bool SmartPtrModeling::evalCall(const CallExpr *CE, CheckerContext &C) const {
6058

6159
// TODO: Add a note to bug reports describing this decision.
6260
C.addTransition(
63-
State->BindExpr(CE, C.getLocationContext(),
64-
C.getSValBuilder().makeZeroVal(CE->getType())));
61+
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
62+
C.getSValBuilder().makeZeroVal(Call.getResultType())));
6563
return true;
6664
}
6765

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> {
224224

225225
public:
226226
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
227-
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
227+
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
228228

229229
private:
230230
Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
@@ -367,12 +367,16 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
367367
}
368368
}
369369

370-
bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE,
370+
bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
371371
CheckerContext &C) const {
372-
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
372+
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
373373
if (!FD)
374374
return false;
375375

376+
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
377+
if (!CE)
378+
return false;
379+
376380
Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
377381
if (!FoundSummary)
378382
return false;

0 commit comments

Comments
 (0)