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 CallExpr *CE, 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 CallExpr *CE,
68 CheckerContext &C)
const {
71 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
72 .Case(
"clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
73 .Case(
"clang_analyzer_checkInlined",
74 &ExprInspectionChecker::analyzerCheckInlined)
75 .Case(
"clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
76 .Case(
"clang_analyzer_warnIfReached",
77 &ExprInspectionChecker::analyzerWarnIfReached)
78 .Case(
"clang_analyzer_warnOnDeadSymbol",
79 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
80 .StartsWith(
"clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
81 .StartsWith(
"clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
82 .Case(
"clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
83 .Case(
"clang_analyzer_printState",
84 &ExprInspectionChecker::analyzerPrintState)
85 .Case(
"clang_analyzer_numTimesReached",
86 &ExprInspectionChecker::analyzerNumTimesReached)
87 .Case(
"clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump)
88 .Case(
"clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
89 .Case(
"clang_analyzer_express", &ExprInspectionChecker::analyzerExpress)
95 (this->*Handler)(CE, C);
102 return "Missing assertion argument";
104 ExplodedNode *N = C.getPredecessor();
109 SVal AssertionVal = State->getSVal(Assertion, LC);
111 if (AssertionVal.isUndef())
115 std::tie(StTrue, StFalse) =
116 State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
127 llvm_unreachable(
"Invalid constraint; neither true or false.");
131 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
132 CheckerContext &C)
const {
133 ExplodedNode *N = C.generateNonFatalErrorNode();
134 reportBug(Msg, C.getBugReporter(), N);
138 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
140 ExplodedNode *N)
const {
145 BT.reset(
new BugType(
this,
"Checking analyzer assumptions",
"debug"));
147 BR.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
151 void ExprInspectionChecker::analyzerEval(
const CallExpr *CE,
152 CheckerContext &C)
const {
163 void ExprInspectionChecker::analyzerWarnIfReached(
const CallExpr *CE,
164 CheckerContext &C)
const {
165 reportBug(
"REACHABLE", C);
168 void ExprInspectionChecker::analyzerNumTimesReached(
const CallExpr *CE,
169 CheckerContext &C)
const {
170 ++ReachedStats[CE].NumTimesReached;
171 if (!ReachedStats[CE].ExampleNode) {
173 ReachedStats[CE].ExampleNode = C.generateNonFatalErrorNode();
177 void ExprInspectionChecker::analyzerCheckInlined(
const CallExpr *CE,
178 CheckerContext &C)
const {
192 void ExprInspectionChecker::analyzerExplain(
const CallExpr *CE,
193 CheckerContext &C)
const {
195 reportBug(
"Missing argument for explaining", C);
199 SVal V = C.getSVal(CE->
getArg(0));
200 SValExplainer Ex(C.getASTContext());
201 reportBug(Ex.Visit(V), C);
204 void ExprInspectionChecker::analyzerDump(
const CallExpr *CE,
205 CheckerContext &C)
const {
207 reportBug(
"Missing argument for dumping", C);
211 SVal V = C.getSVal(CE->
getArg(0));
214 llvm::raw_svector_ostream
OS(Str);
216 reportBug(OS.str(), C);
219 void ExprInspectionChecker::analyzerGetExtent(
const CallExpr *CE,
220 CheckerContext &C)
const {
222 reportBug(
"Missing region for obtaining extent", C);
226 auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->
getArg(0)).getAsRegion());
228 reportBug(
"Obtaining extent of a non-region", C);
233 State = State->BindExpr(CE, C.getLocationContext(),
234 MR->getExtent(C.getSValBuilder()));
235 C.addTransition(State);
238 void ExprInspectionChecker::analyzerPrintState(
const CallExpr *CE,
239 CheckerContext &C)
const {
240 C.getState()->dump();
243 void ExprInspectionChecker::analyzerWarnOnDeadSymbol(
const CallExpr *CE,
244 CheckerContext &C)
const {
247 SVal Val = C.getSVal(CE->
getArg(0));
253 State = State->add<MarkedSymbols>(Sym);
254 C.addTransition(State);
257 void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
258 CheckerContext &C)
const {
260 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
261 ExplodedNode *N = C.getPredecessor();
262 for (
auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
264 if (!SymReaper.isDead(Sym))
268 if (ExplodedNode *BugNode = reportBug(
"SYMBOL DEAD", C))
270 State = State->remove<MarkedSymbols>(Sym);
273 for (
auto I : State->get<DenotedSymbols>()) {
275 if (!SymReaper.isLive(Sym))
276 State = State->remove<DenotedSymbols>(Sym);
279 C.addTransition(State, N);
282 void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
283 ExprEngine &Eng)
const {
284 for (
auto Item: ReachedStats) {
285 unsigned NumTimesReached = Item.second.NumTimesReached;
286 ExplodedNode *N = Item.second.ExampleNode;
288 reportBug(llvm::to_string(NumTimesReached), BR, N);
290 ReachedStats.clear();
293 void ExprInspectionChecker::analyzerCrash(
const CallExpr *CE,
294 CheckerContext &C)
const {
298 void ExprInspectionChecker::analyzerHashDump(
const CallExpr *CE,
299 CheckerContext &C)
const {
303 std::string HashContent =
305 C.getLocationContext()->getDecl(), Opts);
307 reportBug(HashContent, C);
310 void ExprInspectionChecker::analyzerDenote(
const CallExpr *CE,
311 CheckerContext &C)
const {
313 reportBug(
"clang_analyzer_denote() requires a symbol and a string literal",
320 reportBug(
"Not a symbol", C);
326 reportBug(
"Not a string literal", C);
332 C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E));
336 class SymbolExpressor
337 :
public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
344 if (
const StringLiteral *
const *SLPtr = State->get<DenotedSymbols>(S)) {
360 std::to_string(S->getRHS().getLimitedValue()) +
361 (S->getRHS().isUnsigned() ?
"U" :
""))
380 return (Twine(
"(") + S->getType().getAsString() +
")" + *Str).
str();
386 void ExprInspectionChecker::analyzerExpress(
const CallExpr *CE,
387 CheckerContext &C)
const {
389 reportBug(
"clang_analyzer_express() requires a symbol", C);
395 reportBug(
"Not a symbol", C);
399 SymbolExpressor V(C.getState());
400 auto Str = V.Visit(Sym);
402 reportBug(
"Unable to express", C);
409 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
410 Mgr.registerChecker<ExprInspectionChecker>();
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
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
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
IgnoreParenCasts - Ignore parentheses and casts.
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 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.