22#include "llvm/Support/raw_ostream.h"
29class DerefBugType :
public BugType {
30 StringRef ArrayMsg, FieldMsg;
33 DerefBugType(CheckerFrontend *FE, StringRef Desc,
const char *AMsg,
34 const char *FMsg =
nullptr)
35 : BugType(FE, Desc), ArrayMsg(AMsg), FieldMsg(FMsg ? FMsg : AMsg) {}
36 StringRef getArrayMsg()
const {
return ArrayMsg; }
37 StringRef getFieldMsg()
const {
return FieldMsg; }
40class DereferenceChecker
42 EventDispatcher<ImplicitNullDerefEvent>> {
43 void reportBug(
const DerefBugType &BT,
ProgramStateRef State,
const Stmt *S,
44 CheckerContext &
C)
const;
46 bool suppressReport(CheckerContext &
C,
const Expr *E)
const;
49 void checkLocation(SVal location,
bool isLoad,
const Stmt* S,
50 CheckerContext &
C)
const;
51 void checkBind(SVal L, SVal
V,
const Stmt *S,
bool AtDeclInit,
52 CheckerContext &
C)
const;
54 static void AddDerefSource(raw_ostream &os,
55 SmallVectorImpl<SourceRange> &Ranges,
56 const Expr *Ex,
const ProgramState *state,
57 const LocationContext *LCtx,
58 bool loadedFrom =
false);
60 CheckerFrontend NullDerefChecker, FixedDerefChecker;
61 const DerefBugType NullBug{&NullDerefChecker,
"Dereference of null pointer",
62 "a null pointer dereference",
63 "a dereference of a null pointer"};
64 const DerefBugType UndefBug{&NullDerefChecker,
65 "Dereference of undefined pointer value",
66 "an undefined pointer dereference",
67 "a dereference of an undefined pointer value"};
68 const DerefBugType LabelBug{&NullDerefChecker,
69 "Dereference of the address of a label",
70 "an undefined pointer dereference",
71 "a dereference of an address of a label"};
72 const DerefBugType FixedAddressBug{&FixedDerefChecker,
73 "Dereference of a fixed address",
74 "a dereference of a fixed address"};
76 StringRef getDebugTag()
const override {
return "DereferenceChecker"; }
81DereferenceChecker::AddDerefSource(raw_ostream &os,
91 case Stmt::DeclRefExprClass: {
93 if (
const VarDecl *VD = dyn_cast<VarDecl>(DR->
getDecl())) {
94 os <<
" (" << (loadedFrom ?
"loaded from" :
"from")
95 <<
" variable '" << VD->getName() <<
"')";
100 case Stmt::MemberExprClass: {
102 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
105 Ranges.push_back(SourceRange(L, L));
108 case Stmt::ObjCIvarRefExprClass: {
110 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
113 Ranges.push_back(SourceRange(L, L));
120 const Expr *E =
nullptr;
124 if (
const Expr *
expr = dyn_cast<Expr>(S))
125 E =
expr->IgnoreParenLValueCasts();
137bool DereferenceChecker::suppressReport(CheckerContext &
C,
138 const Expr *E)
const {
151 if (
C.getAnalysisManager()
152 .getAnalyzerOptions()
153 .ShouldSuppressAddressSpaceDereferences)
156 const llvm::Triple::ArchType
Arch =
157 C.getASTContext().getTargetInfo().getTriple().getArch();
159 if ((
Arch == llvm::Triple::x86) || (
Arch == llvm::Triple::x86_64)) {
171 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E))
172 return DRE->getDecl()->getType()->isReferenceType();
176void DereferenceChecker::reportBug(
const DerefBugType &BT,
178 CheckerContext &
C)
const {
179 if (&BT == &FixedAddressBug) {
192 ExplodedNode *N =
C.generateErrorNode(State);
196 SmallString<100> Buf;
197 llvm::raw_svector_ostream
Out(Buf);
199 SmallVector<SourceRange, 2> Ranges;
202 case Stmt::ArraySubscriptExprClass: {
203 Out <<
"Array access";
207 Out <<
" results in " << BT.getArrayMsg();
210 case Stmt::ArraySectionExprClass: {
211 Out <<
"Array access";
215 Out <<
" results in " << BT.getArrayMsg();
218 case Stmt::UnaryOperatorClass: {
219 Out << BT.getDescription();
225 case Stmt::MemberExprClass: {
235 case Stmt::ObjCIvarRefExprClass: {
237 Out <<
"Access to instance variable '" << *IV->
getDecl() <<
"' results in "
247 auto BR = std::make_unique<PathSensitiveBugReport>(
248 BT, Buf.empty() ? BT.getDescription() : Buf.str(), N);
252 for (SmallVectorImpl<SourceRange>::iterator
253 I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
256 C.emitReport(std::move(BR));
259void DereferenceChecker::checkLocation(SVal l,
bool isLoad,
const Stmt* S,
260 CheckerContext &
C)
const {
264 if (!suppressReport(
C, DerefExpr))
265 reportBug(UndefBug,
C.getState(), DerefExpr,
C);
269 DefinedOrUnknownSVal location = l.
castAs<DefinedOrUnknownSVal>();
278 std::tie(notNullState, nullState) = state->assume(location);
285 if (!suppressReport(
C,
expr)) {
286 reportBug(NullBug, nullState,
expr,
C);
294 if (ExplodedNode *N =
C.generateSink(nullState,
C.getPredecessor())) {
295 ImplicitNullDerefEvent
event = {l, isLoad, N, &
C.getBugReporter(),
297 dispatchEvent(event);
303 if (!suppressReport(
C, DerefExpr))
304 reportBug(FixedAddressBug, notNullState, DerefExpr,
C);
309 C.addTransition(notNullState);
312void DereferenceChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
313 bool AtDeclInit, CheckerContext &
C)
const {
319 if (
auto Label = L.
getAs<loc::GotoLabel>()) {
320 reportBug(LabelBug,
C.getState(), S,
C);
325 const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
335 std::tie(StNonNull, StNull) = State->assume(
V.castAs<DefinedOrUnknownSVal>());
340 if (!suppressReport(
C,
expr)) {
341 reportBug(NullBug, StNull,
expr,
C);
348 if (ExplodedNode *N =
C.generateSink(StNull,
C.getPredecessor())) {
349 ImplicitNullDerefEvent
event = {
V,
true, N,
352 dispatchEvent(event);
356 if (
V.isConstant()) {
358 if (!suppressReport(
C, DerefExpr))
359 reportBug(FixedAddressBug, State, DerefExpr,
C);
379 C.addTransition(State,
this);
382void ento::registerNullDereferenceChecker(CheckerManager &Mgr) {
383 Mgr.
getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr);
386bool ento::shouldRegisterNullDereferenceChecker(
const CheckerManager &) {
390void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) {
391 Mgr.
getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr);
394bool ento::shouldRegisterFixedAddressDereferenceChecker(
395 const CheckerManager &) {
static const Expr * getDereferenceExpr(const Stmt *S, bool IsBind=false)
static bool isDeclRefExprToReference(const Expr *E)
Expr * getBase()
Get base of the array section.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses 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 ...
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
DeclarationNameInfo getMemberNameInfo() const
Retrieve the member declaration name info.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
SourceLocation getLocation() const
const Expr * getBase() const
LangAS getAddressSpace() const
Return the address space of this type.
bool hasAddressSpace() const
Check if this type has any address space qualifier.
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isReferenceType() const
Expr * getSubExpr() const
Represents a variable declaration or definition.
Checker families (where a single backend class implements multiple related frontends) should derive f...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
const LocationContext * getLocationContext() const
ProgramState - This class encapsulates:
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
virtual QualType getValueType() const =0
Defines the clang::TargetInfo interface.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
unsigned toTargetAddressSpace(LangAS AS)
U cast(CodeGen::Address addr)