18#include "llvm/ADT/StringSwitch.h"
19#include "llvm/Support/ScopedPrinter.h"
26class ExprInspectionChecker
27 :
public Checker<eval::Call, check::DeadSymbols, check::EndAnalysis> {
28 const BugType BT{
this,
"Checking analyzer assumptions",
"debug"};
33 ExplodedNode *ExampleNode;
34 unsigned NumTimesReached;
36 mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats;
38 void analyzerEval(
const CallExpr *CE, CheckerContext &
C)
const;
39 void analyzerCheckInlined(
const CallExpr *CE, CheckerContext &
C)
const;
40 void analyzerWarnIfReached(
const CallExpr *CE, CheckerContext &
C)
const;
41 void analyzerNumTimesReached(
const CallExpr *CE, CheckerContext &
C)
const;
42 void analyzerCrash(
const CallExpr *CE, CheckerContext &
C)
const;
43 void analyzerWarnOnDeadSymbol(
const CallExpr *CE, CheckerContext &
C)
const;
44 void analyzerValue(
const CallExpr *CE, CheckerContext &
C)
const;
45 void analyzerDumpSValType(
const CallExpr *CE, CheckerContext &
C)
const;
46 void analyzerDump(
const CallExpr *CE, CheckerContext &
C)
const;
47 void analyzerExplain(
const CallExpr *CE, CheckerContext &
C)
const;
48 void analyzerPrintState(
const CallExpr *CE, CheckerContext &
C)
const;
49 void analyzerGetExtent(
const CallExpr *CE, CheckerContext &
C)
const;
50 void analyzerDumpExtent(
const CallExpr *CE, CheckerContext &
C)
const;
51 void analyzerDumpElementCount(
const CallExpr *CE, CheckerContext &
C)
const;
52 void analyzerHashDump(
const CallExpr *CE, CheckerContext &
C)
const;
53 void analyzerDenote(
const CallExpr *CE, CheckerContext &
C)
const;
54 void analyzerExpress(
const CallExpr *CE, CheckerContext &
C)
const;
55 void analyzerIsTainted(
const CallExpr *CE, CheckerContext &
C)
const;
57 typedef void (ExprInspectionChecker::*FnCheck)(
const CallExpr *,
58 CheckerContext &
C)
const;
61 ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &
C,
62 std::optional<SVal> ExprVal = std::nullopt)
const;
63 ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, ExplodedNode *N,
64 std::optional<SVal> ExprVal = std::nullopt)
const;
65 template <
typename T>
void printAndReport(CheckerContext &
C,
T What)
const;
67 const Expr *getArgExpr(
const CallExpr *CE, CheckerContext &
C)
const;
68 const MemRegion *getArgRegion(
const CallExpr *CE, CheckerContext &
C)
const;
71 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
72 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const;
73 void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
74 ExprEngine &Eng)
const;
83 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
90 llvm::StringSwitch<FnCheck>(
C.getCalleeName(CE))
91 .Case(
"clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
92 .Case(
"clang_analyzer_checkInlined",
93 &ExprInspectionChecker::analyzerCheckInlined)
94 .Case(
"clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
95 .Case(
"clang_analyzer_warnIfReached",
96 &ExprInspectionChecker::analyzerWarnIfReached)
97 .Case(
"clang_analyzer_warnOnDeadSymbol",
98 &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
99 .StartsWith(
"clang_analyzer_explain",
100 &ExprInspectionChecker::analyzerExplain)
101 .Case(
"clang_analyzer_dumpExtent",
102 &ExprInspectionChecker::analyzerDumpExtent)
103 .Case(
"clang_analyzer_dumpElementCount",
104 &ExprInspectionChecker::analyzerDumpElementCount)
105 .Case(
"clang_analyzer_value", &ExprInspectionChecker::analyzerValue)
106 .StartsWith(
"clang_analyzer_dumpSvalType",
107 &ExprInspectionChecker::analyzerDumpSValType)
108 .StartsWith(
"clang_analyzer_dump",
109 &ExprInspectionChecker::analyzerDump)
110 .Case(
"clang_analyzer_getExtent",
111 &ExprInspectionChecker::analyzerGetExtent)
112 .Case(
"clang_analyzer_printState",
113 &ExprInspectionChecker::analyzerPrintState)
114 .Case(
"clang_analyzer_numTimesReached",
115 &ExprInspectionChecker::analyzerNumTimesReached)
116 .Case(
"clang_analyzer_hashDump",
117 &ExprInspectionChecker::analyzerHashDump)
118 .Case(
"clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
119 .Case(
"clang_analyzer_express",
121 &ExprInspectionChecker::analyzerExpress)
122 .StartsWith(
"clang_analyzer_isTainted",
123 &ExprInspectionChecker::analyzerIsTainted)
129 (this->*Handler)(CE,
C);
136 return "Missing assertion argument";
143 SVal AssertionVal = State->getSVal(Assertion, LC);
149 std::tie(StTrue, StFalse) =
161 llvm_unreachable(
"Invalid constraint; neither true or false.");
166ExprInspectionChecker::reportBug(llvm::StringRef Msg, CheckerContext &
C,
167 std::optional<SVal> ExprVal)
const {
168 ExplodedNode *N =
C.generateNonFatalErrorNode();
169 reportBug(Msg,
C.getBugReporter(), N, ExprVal);
174ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR,
176 std::optional<SVal> ExprVal)
const {
179 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
181 R->markInteresting(*ExprVal);
187const Expr *ExprInspectionChecker::getArgExpr(
const CallExpr *CE,
188 CheckerContext &
C)
const {
190 reportBug(
"Missing argument",
C);
196const MemRegion *ExprInspectionChecker::getArgRegion(
const CallExpr *CE,
197 CheckerContext &
C)
const {
198 const Expr *Arg = getArgExpr(CE,
C);
202 const MemRegion *MR =
C.getSVal(Arg).getAsRegion();
204 reportBug(
"Cannot obtain the region",
C);
211void ExprInspectionChecker::analyzerEval(
const CallExpr *CE,
212 CheckerContext &
C)
const {
213 const LocationContext *LC =
C.getPredecessor()->getLocationContext();
223void ExprInspectionChecker::analyzerWarnIfReached(
const CallExpr *CE,
224 CheckerContext &
C)
const {
225 reportBug(
"REACHABLE",
C);
228void ExprInspectionChecker::analyzerNumTimesReached(
const CallExpr *CE,
229 CheckerContext &
C)
const {
230 ReachedStat &Stat = ReachedStats[CE];
231 ++Stat.NumTimesReached;
232 if (!Stat.ExampleNode) {
234 Stat.ExampleNode =
C.generateNonFatalErrorNode();
238void ExprInspectionChecker::analyzerCheckInlined(
const CallExpr *CE,
239 CheckerContext &
C)
const {
240 const LocationContext *LC =
C.getPredecessor()->getLocationContext();
253void ExprInspectionChecker::analyzerExplain(
const CallExpr *CE,
254 CheckerContext &
C)
const {
255 const Expr *Arg = getArgExpr(CE,
C);
259 SVal
V =
C.getSVal(Arg);
260 SValExplainer Ex(
C.getASTContext(),
C.getState());
261 reportBug(Ex.Visit(
V),
C);
265 const llvm::APSInt &I) {
266 Out << I.getBitWidth() << (I.isUnsigned() ?
"u:" :
"s:");
272 C.getConstraintManager().printValue(Out,
C.getState(), Sym);
281void ExprInspectionChecker::printAndReport(CheckerContext &
C,
T What)
const {
282 llvm::SmallString<64> Str;
283 llvm::raw_svector_ostream
OS(Str);
285 reportBug(
OS.str(),
C);
288void ExprInspectionChecker::analyzerValue(
const CallExpr *CE,
289 CheckerContext &
C)
const {
290 const Expr *Arg = getArgExpr(CE,
C);
294 SVal
V =
C.getSVal(Arg);
296 printAndReport(
C, Sym);
297 else if (
const llvm::APSInt *I =
V.getAsInteger())
298 printAndReport(
C, *I);
303void ExprInspectionChecker::analyzerDumpSValType(
const CallExpr *CE,
304 CheckerContext &
C)
const {
305 const Expr *Arg = getArgExpr(CE,
C);
309 QualType Ty =
C.getSVal(Arg).getType(
C.getASTContext());
313void ExprInspectionChecker::analyzerDump(
const CallExpr *CE,
314 CheckerContext &
C)
const {
315 const Expr *Arg = getArgExpr(CE,
C);
319 SVal
V =
C.getSVal(Arg);
320 printAndReport(
C,
V);
323void ExprInspectionChecker::analyzerGetExtent(
const CallExpr *CE,
324 CheckerContext &
C)
const {
325 const Expr *Arg = getArgExpr(CE,
C);
332 State = State->BindExpr(CE,
C.getLocationContext(), Size);
333 C.addTransition(State);
336void ExprInspectionChecker::analyzerDumpExtent(
const CallExpr *CE,
337 CheckerContext &
C)
const {
338 const Expr *Arg = getArgExpr(CE,
C);
344 printAndReport(
C, Size);
347void ExprInspectionChecker::analyzerDumpElementCount(
const CallExpr *CE,
348 CheckerContext &
C)
const {
349 const MemRegion *MR = getArgRegion(CE,
C);
354 if (
const auto *TVR = MR->
getAs<TypedValueRegion>()) {
355 ElementTy = TVR->getValueType();
357 ElementTy = MR->
castAs<SymbolicRegion>()->getPointeeStaticType();
363 C.getState(),
C.getSVal(getArgExpr(CE,
C)), ElementTy);
364 printAndReport(
C, ElementCount);
367void ExprInspectionChecker::analyzerPrintState(
const CallExpr *CE,
368 CheckerContext &
C)
const {
369 C.getState()->dump();
372void ExprInspectionChecker::analyzerWarnOnDeadSymbol(
const CallExpr *CE,
373 CheckerContext &
C)
const {
374 const Expr *Arg = getArgExpr(CE,
C);
378 SVal Val =
C.getSVal(Arg);
384 State = State->add<MarkedSymbols>(Sym);
385 C.addTransition(State);
388void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper,
389 CheckerContext &
C)
const {
391 const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
392 ExplodedNode *N =
C.getPredecessor();
394 if (!SymReaper.
isDead(Sym))
398 if (ExplodedNode *BugNode = reportBug(
"SYMBOL DEAD",
C))
400 State = State->remove<MarkedSymbols>(Sym);
403 for (
auto I : State->get<DenotedSymbols>()) {
405 if (!SymReaper.
isLive(Sym))
406 State = State->remove<DenotedSymbols>(Sym);
409 C.addTransition(State, N);
412void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
413 ExprEngine &Eng)
const {
414 for (
auto Item : ReachedStats) {
415 unsigned NumTimesReached = Item.second.NumTimesReached;
416 ExplodedNode *N = Item.second.ExampleNode;
418 reportBug(llvm::to_string(NumTimesReached), BR, N);
420 ReachedStats.clear();
423void ExprInspectionChecker::analyzerCrash(
const CallExpr *CE,
424 CheckerContext &
C)
const {
428void ExprInspectionChecker::analyzerHashDump(
const CallExpr *CE,
429 CheckerContext &
C)
const {
430 const LangOptions &Opts =
C.getLangOpts();
431 const SourceManager &
SM =
C.getSourceManager();
434 FL,
getName(),
"Category",
C.getLocationContext()->getDecl(), Opts);
436 reportBug(HashContent,
C);
439void ExprInspectionChecker::analyzerDenote(
const CallExpr *CE,
440 CheckerContext &
C)
const {
442 reportBug(
"clang_analyzer_denote() requires a symbol and a string literal",
449 reportBug(
"Not a symbol",
C);
455 reportBug(
"Not a string literal",
C);
461 C.addTransition(
C.getState()->set<DenotedSymbols>(Sym, E));
466 :
public SymExprVisitor<SymbolExpressor, std::optional<std::string>> {
472 std::optional<std::string> lookup(
const SymExpr *S) {
473 if (
const StringLiteral *
const *SLPtr = State->get<DenotedSymbols>(S)) {
474 const StringLiteral *SL = *SLPtr;
480 std::optional<std::string> VisitSymExpr(
const SymExpr *S) {
484 std::optional<std::string> VisitSymIntExpr(
const SymIntExpr *S) {
485 if (std::optional<std::string> Str = lookup(S))
487 if (std::optional<std::string> Str = Visit(S->
getLHS()))
489 std::to_string(S->
getRHS()->getLimitedValue()) +
490 (S->
getRHS()->isUnsigned() ?
"U" :
""))
495 std::optional<std::string> VisitSymSymExpr(
const SymSymExpr *S) {
496 if (std::optional<std::string> Str = lookup(S))
498 if (std::optional<std::string> Str1 = Visit(S->
getLHS()))
499 if (std::optional<std::string> Str2 = Visit(S->
getRHS()))
506 std::optional<std::string> VisitUnarySymExpr(
const UnarySymExpr *S) {
507 if (std::optional<std::string> Str = lookup(S))
509 if (std::optional<std::string> Str = Visit(S->
getOperand()))
514 std::optional<std::string> VisitSymbolCast(
const SymbolCast *S) {
515 if (std::optional<std::string> Str = lookup(S))
517 if (std::optional<std::string> Str = Visit(S->
getOperand()))
524void ExprInspectionChecker::analyzerExpress(
const CallExpr *CE,
525 CheckerContext &
C)
const {
526 const Expr *Arg = getArgExpr(CE,
C);
530 SVal ArgVal =
C.getSVal(CE->
getArg(0));
533 reportBug(
"Not a symbol",
C, ArgVal);
537 SymbolExpressor
V(
C.getState());
538 auto Str =
V.Visit(Sym);
540 reportBug(
"Unable to express",
C, ArgVal);
544 reportBug(*Str,
C, ArgVal);
547void ExprInspectionChecker::analyzerIsTainted(
const CallExpr *CE,
548 CheckerContext &
C)
const {
550 reportBug(
"clang_analyzer_isTainted() requires exactly one argument",
C);
553 const bool IsTainted =
555 reportBug(IsTainted ?
"YES" :
"NO",
C);
558void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
562bool ento::shouldRegisterExprInspectionChecker(
const CheckerManager &mgr) {
static void printHelper(llvm::raw_svector_ostream &Out, CheckerContext &C, const llvm::APSInt &I)
static const char * getArgumentValueString(const CallExpr *CE, CheckerContext &C)
#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.
StringRef getOpcodeStr() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
SourceLocation getBeginLoc() const LLVM_READONLY
StringLiteral - This represents a string literal expression, e.g.
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
bool isPointerType() const
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
BinaryOperator::Opcode getOpcode() const
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const ProgramStateRef & getState() const
const LocationContext * getLocationContext() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const RegionTy * castAs() const
const RegionTy * getAs() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
QualType getType() const override
LLVM_ATTRIBUTE_RETURNS_NONNULL const SymExpr * getOperand() const
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
bool isLive(SymbolRef sym)
UnaryOperator::Opcode getOpcode() const
const SymExpr * getOperand() const
bool isTainted(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Check if the statement has a tainted value in the given state.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV)
Get the dynamic extent for a symbolic value that represents a buffer.
const SymExpr * SymbolRef
BinarySymExprImpl< const SymExpr *, const SymExpr *, SymExpr::Kind::SymSymExprKind > SymSymExpr
Represents a symbolic expression like 'x' + 'y'.
BinarySymExprImpl< const SymExpr *, APSIntPtr, SymExpr::Kind::SymIntExprKind > SymIntExpr
Represents a symbolic expression like 'x' + 3.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State, SVal BufV, QualType Ty)
StringRef getName(const HeaderType T)
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
std::string getIssueString(const FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef WarningMessage, const Decl *IssueDecl, const LangOptions &LangOpts)
Get the unhashed string representation of the V1 issue hash.