16 #include "llvm/ADT/StringSwitch.h" 17 #include "llvm/Support/ScopedPrinter.h" 19 using namespace clang;
23 class ExprInspectionChecker :
public Checker<eval::Call, check::DeadSymbols,
25 mutable std::unique_ptr<BugType> BT;
30 ExplodedNode *ExampleNode;
31 unsigned NumTimesReached;
33 mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
35 void analyzerEval(
const CallExpr *CE, CheckerContext &C)
const;
36 void analyzerCheckInlined(
const CallExpr *CE, CheckerContext &C)
const;
37 void analyzerWarnIfReached(
const CallExpr *CE, CheckerContext &C)
const;
38 void analyzerNumTimesReached(
const CallExpr *CE, CheckerContext &C)
const;
39 void analyzerCrash(
const CallExpr *CE, CheckerContext &C)
const;
40 void analyzerWarnOnDeadSymbol(
const CallExpr *CE, CheckerContext &C)
const;
41 void analyzerDump(
const CallExpr *CE, CheckerContext &C)
const;
42 void analyzerExplain(
const CallExpr *CE, CheckerContext &C)
const;
43 void analyzerPrintState(
const CallExpr *CE, CheckerContext &C)
const;
44 void analyzerGetExtent(
const CallExpr *CE, CheckerContext &C)
const;
45 void analyzerHashDump(
const CallExpr *CE, CheckerContext &C)
const;
46 void analyzerDenote(
const CallExpr *CE, CheckerContext &C)
const;
47 void analyzerExpress(
const CallExpr *CE, CheckerContext &C)
const;
49 typedef void (ExprInspectionChecker::*FnCheck)(
const CallExpr *,
50 CheckerContext &
C)
const;
52 ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C)
const;
53 ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR,
54 ExplodedNode *N)
const;
57 bool evalCall(
const CallEvent &Call, CheckerContext &C)
const;
58 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const;
59 void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
60 ExprEngine &Eng)
const;
67 bool ExprInspectionChecker::evalCall(
const CallEvent &Call,
68 CheckerContext &C)
const {
69 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
75 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
76 .Case(
"clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
77 .Case(
"clang_analyzer_checkInlined",
78 &ExprInspectionChecker::analyzerCheckInlined)
79 .Case(
"clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
80 .Case(
"clang_analyzer_warnIfReached",
81 &ExprInspectionChecker::analyzerWarnIfReached)
82 .Case(
"clang_analyzer_warnOnDeadSymbol",
83 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
84 .StartsWith(
"clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
85 .StartsWith(
"clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
86 .Case(
"clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
87 .Case(
"clang_analyzer_printState",
88 &ExprInspectionChecker::analyzerPrintState)
89 .Case(
"clang_analyzer_numTimesReached",
90 &ExprInspectionChecker::analyzerNumTimesReached)
91 .Case(
"clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump)
92 .Case(
"clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
93 .Case(
"clang_analyzer_express", &ExprInspectionChecker::analyzerExpress)
99 (this->*Handler)(CE, C);
106 return "Missing assertion argument";
108 ExplodedNode *N = C.getPredecessor();
113 SVal AssertionVal = State->getSVal(Assertion, LC);
115 if (AssertionVal.isUndef())
119 std::tie(StTrue, StFalse) =
120 State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
131 llvm_unreachable(
"Invalid constraint; neither true or false.");
135 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
136 CheckerContext &C)
const {
137 ExplodedNode *N = C.generateNonFatalErrorNode();
138 reportBug(Msg, C.getBugReporter(), N);
142 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
144 ExplodedNode *N)
const {
149 BT.reset(
new BugType(
this,
"Checking analyzer assumptions",
"debug"));
151 BR.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
155 void ExprInspectionChecker::analyzerEval(
const CallExpr *CE,
156 CheckerContext &C)
const {
167 void ExprInspectionChecker::analyzerWarnIfReached(
const CallExpr *CE,
168 CheckerContext &C)
const {
169 reportBug(
"REACHABLE", C);
172 void ExprInspectionChecker::analyzerNumTimesReached(
const CallExpr *CE,
173 CheckerContext &C)
const {
174 ++ReachedStats[CE].NumTimesReached;
175 if (!ReachedStats[CE].ExampleNode) {
177 ReachedStats[CE].ExampleNode = C.generateNonFatalErrorNode();
181 void ExprInspectionChecker::analyzerCheckInlined(
const CallExpr *CE,
182 CheckerContext &C)
const {
196 void ExprInspectionChecker::analyzerExplain(
const CallExpr *CE,
197 CheckerContext &C)
const {
199 reportBug(
"Missing argument for explaining", C);
203 SVal
V = C.getSVal(CE->
getArg(0));
204 SValExplainer Ex(C.getASTContext());
205 reportBug(Ex.Visit(V), C);
208 void ExprInspectionChecker::analyzerDump(
const CallExpr *CE,
209 CheckerContext &C)
const {
211 reportBug(
"Missing argument for dumping", C);
215 SVal
V = C.getSVal(CE->
getArg(0));
218 llvm::raw_svector_ostream
OS(Str);
220 reportBug(OS.str(), C);
223 void ExprInspectionChecker::analyzerGetExtent(
const CallExpr *CE,
224 CheckerContext &C)
const {
226 reportBug(
"Missing region for obtaining extent", C);
230 auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->
getArg(0)).getAsRegion());
232 reportBug(
"Obtaining extent of a non-region", C);
237 State = State->BindExpr(CE, C.getLocationContext(),
238 MR->getExtent(C.getSValBuilder()));
239 C.addTransition(State);
242 void ExprInspectionChecker::analyzerPrintState(
const CallExpr *CE,
243 CheckerContext &C)
const {
244 C.getState()->dump();
247 void ExprInspectionChecker::analyzerWarnOnDeadSymbol(
const CallExpr *CE,
248 CheckerContext &C)
const {
251 SVal Val = C.getSVal(CE->
getArg(0));
257 State = State->add<MarkedSymbols>(Sym);
258 C.addTransition(State);
261 void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
262 CheckerContext &C)
const {
264 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
265 ExplodedNode *N = C.getPredecessor();
266 for (
auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
268 if (!SymReaper.isDead(Sym))
272 if (ExplodedNode *BugNode = reportBug(
"SYMBOL DEAD", C))
274 State = State->remove<MarkedSymbols>(Sym);
277 for (
auto I : State->get<DenotedSymbols>()) {
279 if (!SymReaper.isLive(Sym))
280 State = State->remove<DenotedSymbols>(Sym);
283 C.addTransition(State, N);
286 void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
287 ExprEngine &Eng)
const {
288 for (
auto Item: ReachedStats) {
289 unsigned NumTimesReached = Item.second.NumTimesReached;
290 ExplodedNode *N = Item.second.ExampleNode;
292 reportBug(llvm::to_string(NumTimesReached), BR, N);
294 ReachedStats.clear();
297 void ExprInspectionChecker::analyzerCrash(
const CallExpr *CE,
298 CheckerContext &C)
const {
302 void ExprInspectionChecker::analyzerHashDump(
const CallExpr *CE,
303 CheckerContext &C)
const {
307 std::string HashContent =
309 C.getLocationContext()->getDecl(), Opts);
311 reportBug(HashContent, C);
314 void ExprInspectionChecker::analyzerDenote(
const CallExpr *CE,
315 CheckerContext &C)
const {
317 reportBug(
"clang_analyzer_denote() requires a symbol and a string literal",
324 reportBug(
"Not a symbol", C);
330 reportBug(
"Not a string literal", C);
336 C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E));
340 class SymbolExpressor
341 :
public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
348 if (
const StringLiteral *
const *SLPtr = State->get<DenotedSymbols>(S)) {
364 std::to_string(S->getRHS().getLimitedValue()) +
365 (S->getRHS().isUnsigned() ?
"U" :
""))
384 return (Twine(
"(") + S->getType().getAsString() +
")" + *Str).str();
390 void ExprInspectionChecker::analyzerExpress(
const CallExpr *CE,
391 CheckerContext &C)
const {
393 reportBug(
"clang_analyzer_express() requires a symbol", C);
399 reportBug(
"Not a symbol", C);
403 SymbolExpressor
V(C.getState());
404 auto Str =
V.Visit(Sym);
406 reportBug(
"Unable to express", C);
413 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
414 Mgr.registerChecker<ExprInspectionChecker>();
417 bool ento::shouldRegisterExprInspectionChecker(
const LangOptions &LO) {
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
const SymExpr * SymbolRef
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
SourceLocation getBeginLoc() const LLVM_READONLY
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
StringRef getOpcodeStr() const
const LocationContext * getParent() const
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
This represents one expression.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Dataflow Directional Tag Classes.
static std::string getName(const CallEvent &Call)
static const char * getArgumentValueString(const CallExpr *CE, CheckerContext &C)
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
const StackFrameContext * getStackFrame() const
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef BugType, const Decl *D, const LangOptions &LangOpts)
Get the string representation of issue hash.
StringLiteral - This represents a string literal expression, e.g.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A SourceLocation and its associated SourceManager.
This class handles loading and caching of source files into memory.