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;
31 unsigned NumTimesReached;
33 mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
47 typedef void (ExprInspectionChecker::*FnCheck)(
const CallExpr *,
64 bool ExprInspectionChecker::evalCall(
const CallExpr *CE,
68 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.
getCalleeName(CE))
69 .Case(
"clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
70 .Case(
"clang_analyzer_checkInlined",
71 &ExprInspectionChecker::analyzerCheckInlined)
72 .Case(
"clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
73 .Case(
"clang_analyzer_warnIfReached",
74 &ExprInspectionChecker::analyzerWarnIfReached)
75 .Case(
"clang_analyzer_warnOnDeadSymbol",
76 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
77 .StartsWith(
"clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
78 .StartsWith(
"clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
79 .Case(
"clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
80 .Case(
"clang_analyzer_printState",
81 &ExprInspectionChecker::analyzerPrintState)
82 .Case(
"clang_analyzer_numTimesReached",
83 &ExprInspectionChecker::analyzerNumTimesReached)
84 .Case(
"clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump)
90 (this->*Handler)(CE, C);
97 return "Missing assertion argument";
104 SVal AssertionVal = State->getSVal(Assertion, LC);
110 std::tie(StTrue, StFalse) =
122 llvm_unreachable(
"Invalid constraint; neither true or false.");
126 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
133 ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
140 BT.reset(
new BugType(
this,
"Checking analyzer assumptions",
"debug"));
142 BR.
emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
146 void ExprInspectionChecker::analyzerEval(
const CallExpr *CE,
158 void ExprInspectionChecker::analyzerWarnIfReached(
const CallExpr *CE,
160 reportBug(
"REACHABLE", C);
163 void ExprInspectionChecker::analyzerNumTimesReached(
const CallExpr *CE,
165 ++ReachedStats[CE].NumTimesReached;
166 if (!ReachedStats[CE].ExampleNode) {
172 void ExprInspectionChecker::analyzerCheckInlined(
const CallExpr *CE,
187 void ExprInspectionChecker::analyzerExplain(
const CallExpr *CE,
190 reportBug(
"Missing argument for explaining", C);
196 reportBug(Ex.Visit(V), C);
199 void ExprInspectionChecker::analyzerDump(
const CallExpr *CE,
202 reportBug(
"Missing argument for dumping", C);
209 llvm::raw_svector_ostream OS(Str);
211 reportBug(OS.str(), C);
214 void ExprInspectionChecker::analyzerGetExtent(
const CallExpr *CE,
217 reportBug(
"Missing region for obtaining extent", C);
221 auto MR = dyn_cast_or_null<SubRegion>(C.
getSVal(CE->
getArg(0)).getAsRegion());
223 reportBug(
"Obtaining extent of a non-region", C);
233 void ExprInspectionChecker::analyzerPrintState(
const CallExpr *CE,
238 void ExprInspectionChecker::analyzerWarnOnDeadSymbol(
const CallExpr *CE,
248 State = State->add<MarkedSymbols>(Sym);
252 void ExprInspectionChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
255 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
257 for (
auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
259 if (!SymReaper.
isDead(Sym))
263 if (
ExplodedNode *BugNode = reportBug(
"SYMBOL DEAD", C))
265 State = State->remove<MarkedSymbols>(Sym);
272 for (
auto Item: ReachedStats) {
273 unsigned NumTimesReached = Item.second.NumTimesReached;
276 reportBug(llvm::to_string(NumTimesReached), BR, N);
278 ReachedStats.clear();
281 void ExprInspectionChecker::analyzerCrash(
const CallExpr *CE,
286 void ExprInspectionChecker::analyzerHashDump(
const CallExpr *CE,
291 std::string HashContent =
295 reportBug(HashContent, C);
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const ProgramStateRef & getState() const
bool isDead(SymbolRef sym) const
Returns whether or not a symbol has been confirmed dead.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
StringRef getCalleeName(const FunctionDecl *FunDecl) const
Get the name of the called function (path-sensitive).
void dumpToStream(raw_ostream &OS) const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
BugReporter & getBugReporter()
const StackFrameContext * getCurrentStackFrame() const
const LocationContext * getLocationContext() const
const LocationContext * getParent() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Expr - This represents one expression.
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
BugReporter is a utility class for generating PathDiagnostics for analysis.
CHECKER * registerChecker()
Used to register checkers.
void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
A class responsible for cleaning up unused symbols.
Dataflow Directional Tag Classes.
ASTContext & getASTContext()
static const char * getArgumentValueString(const CallExpr *CE, CheckerContext &C)
const Decl * getDecl() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
const ProgramStateRef & getState() const
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.
SourceManager & getSourceManager()
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A SourceLocation and its associated SourceManager.
const LocationContext * getLocationContext() const
SourceLocation getLocStart() const LLVM_READONLY
This class handles loading and caching of source files into memory.
const LangOptions & getLangOpts() const