1*67e74705SXin Li //== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This defines NullDerefChecker, a builtin check in ExprEngine that performs
11*67e74705SXin Li // checks for null pointers at loads and stores.
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li
15*67e74705SXin Li #include "ClangSACheckers.h"
16*67e74705SXin Li #include "clang/AST/ExprObjC.h"
17*67e74705SXin Li #include "clang/AST/ExprOpenMP.h"
18*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
23*67e74705SXin Li #include "llvm/ADT/SmallString.h"
24*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
25*67e74705SXin Li
26*67e74705SXin Li using namespace clang;
27*67e74705SXin Li using namespace ento;
28*67e74705SXin Li
29*67e74705SXin Li namespace {
30*67e74705SXin Li class DereferenceChecker
31*67e74705SXin Li : public Checker< check::Location,
32*67e74705SXin Li check::Bind,
33*67e74705SXin Li EventDispatcher<ImplicitNullDerefEvent> > {
34*67e74705SXin Li mutable std::unique_ptr<BuiltinBug> BT_null;
35*67e74705SXin Li mutable std::unique_ptr<BuiltinBug> BT_undef;
36*67e74705SXin Li
37*67e74705SXin Li void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const;
38*67e74705SXin Li
39*67e74705SXin Li public:
40*67e74705SXin Li void checkLocation(SVal location, bool isLoad, const Stmt* S,
41*67e74705SXin Li CheckerContext &C) const;
42*67e74705SXin Li void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
43*67e74705SXin Li
44*67e74705SXin Li static void AddDerefSource(raw_ostream &os,
45*67e74705SXin Li SmallVectorImpl<SourceRange> &Ranges,
46*67e74705SXin Li const Expr *Ex, const ProgramState *state,
47*67e74705SXin Li const LocationContext *LCtx,
48*67e74705SXin Li bool loadedFrom = false);
49*67e74705SXin Li };
50*67e74705SXin Li } // end anonymous namespace
51*67e74705SXin Li
52*67e74705SXin Li void
AddDerefSource(raw_ostream & os,SmallVectorImpl<SourceRange> & Ranges,const Expr * Ex,const ProgramState * state,const LocationContext * LCtx,bool loadedFrom)53*67e74705SXin Li DereferenceChecker::AddDerefSource(raw_ostream &os,
54*67e74705SXin Li SmallVectorImpl<SourceRange> &Ranges,
55*67e74705SXin Li const Expr *Ex,
56*67e74705SXin Li const ProgramState *state,
57*67e74705SXin Li const LocationContext *LCtx,
58*67e74705SXin Li bool loadedFrom) {
59*67e74705SXin Li Ex = Ex->IgnoreParenLValueCasts();
60*67e74705SXin Li switch (Ex->getStmtClass()) {
61*67e74705SXin Li default:
62*67e74705SXin Li break;
63*67e74705SXin Li case Stmt::DeclRefExprClass: {
64*67e74705SXin Li const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
65*67e74705SXin Li if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
66*67e74705SXin Li os << " (" << (loadedFrom ? "loaded from" : "from")
67*67e74705SXin Li << " variable '" << VD->getName() << "')";
68*67e74705SXin Li Ranges.push_back(DR->getSourceRange());
69*67e74705SXin Li }
70*67e74705SXin Li break;
71*67e74705SXin Li }
72*67e74705SXin Li case Stmt::MemberExprClass: {
73*67e74705SXin Li const MemberExpr *ME = cast<MemberExpr>(Ex);
74*67e74705SXin Li os << " (" << (loadedFrom ? "loaded from" : "via")
75*67e74705SXin Li << " field '" << ME->getMemberNameInfo() << "')";
76*67e74705SXin Li SourceLocation L = ME->getMemberLoc();
77*67e74705SXin Li Ranges.push_back(SourceRange(L, L));
78*67e74705SXin Li break;
79*67e74705SXin Li }
80*67e74705SXin Li case Stmt::ObjCIvarRefExprClass: {
81*67e74705SXin Li const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
82*67e74705SXin Li os << " (" << (loadedFrom ? "loaded from" : "via")
83*67e74705SXin Li << " ivar '" << IV->getDecl()->getName() << "')";
84*67e74705SXin Li SourceLocation L = IV->getLocation();
85*67e74705SXin Li Ranges.push_back(SourceRange(L, L));
86*67e74705SXin Li break;
87*67e74705SXin Li }
88*67e74705SXin Li }
89*67e74705SXin Li }
90*67e74705SXin Li
getDereferenceExpr(const Stmt * S,bool IsBind=false)91*67e74705SXin Li static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
92*67e74705SXin Li const Expr *E = nullptr;
93*67e74705SXin Li
94*67e74705SXin Li // Walk through lvalue casts to get the original expression
95*67e74705SXin Li // that syntactically caused the load.
96*67e74705SXin Li if (const Expr *expr = dyn_cast<Expr>(S))
97*67e74705SXin Li E = expr->IgnoreParenLValueCasts();
98*67e74705SXin Li
99*67e74705SXin Li if (IsBind) {
100*67e74705SXin Li const VarDecl *VD;
101*67e74705SXin Li const Expr *Init;
102*67e74705SXin Li std::tie(VD, Init) = parseAssignment(S);
103*67e74705SXin Li if (VD && Init)
104*67e74705SXin Li E = Init;
105*67e74705SXin Li }
106*67e74705SXin Li return E;
107*67e74705SXin Li }
108*67e74705SXin Li
suppressReport(const Expr * E)109*67e74705SXin Li static bool suppressReport(const Expr *E) {
110*67e74705SXin Li // Do not report dereferences on memory in non-default address spaces.
111*67e74705SXin Li return E->getType().getQualifiers().hasAddressSpace();
112*67e74705SXin Li }
113*67e74705SXin Li
reportBug(ProgramStateRef State,const Stmt * S,CheckerContext & C) const114*67e74705SXin Li void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
115*67e74705SXin Li CheckerContext &C) const {
116*67e74705SXin Li // Generate an error node.
117*67e74705SXin Li ExplodedNode *N = C.generateErrorNode(State);
118*67e74705SXin Li if (!N)
119*67e74705SXin Li return;
120*67e74705SXin Li
121*67e74705SXin Li // We know that 'location' cannot be non-null. This is what
122*67e74705SXin Li // we call an "explicit" null dereference.
123*67e74705SXin Li if (!BT_null)
124*67e74705SXin Li BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
125*67e74705SXin Li
126*67e74705SXin Li SmallString<100> buf;
127*67e74705SXin Li llvm::raw_svector_ostream os(buf);
128*67e74705SXin Li
129*67e74705SXin Li SmallVector<SourceRange, 2> Ranges;
130*67e74705SXin Li
131*67e74705SXin Li switch (S->getStmtClass()) {
132*67e74705SXin Li case Stmt::ArraySubscriptExprClass: {
133*67e74705SXin Li os << "Array access";
134*67e74705SXin Li const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
135*67e74705SXin Li AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
136*67e74705SXin Li State.get(), N->getLocationContext());
137*67e74705SXin Li os << " results in a null pointer dereference";
138*67e74705SXin Li break;
139*67e74705SXin Li }
140*67e74705SXin Li case Stmt::OMPArraySectionExprClass: {
141*67e74705SXin Li os << "Array access";
142*67e74705SXin Li const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
143*67e74705SXin Li AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
144*67e74705SXin Li State.get(), N->getLocationContext());
145*67e74705SXin Li os << " results in a null pointer dereference";
146*67e74705SXin Li break;
147*67e74705SXin Li }
148*67e74705SXin Li case Stmt::UnaryOperatorClass: {
149*67e74705SXin Li os << "Dereference of null pointer";
150*67e74705SXin Li const UnaryOperator *U = cast<UnaryOperator>(S);
151*67e74705SXin Li AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
152*67e74705SXin Li State.get(), N->getLocationContext(), true);
153*67e74705SXin Li break;
154*67e74705SXin Li }
155*67e74705SXin Li case Stmt::MemberExprClass: {
156*67e74705SXin Li const MemberExpr *M = cast<MemberExpr>(S);
157*67e74705SXin Li if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) {
158*67e74705SXin Li os << "Access to field '" << M->getMemberNameInfo()
159*67e74705SXin Li << "' results in a dereference of a null pointer";
160*67e74705SXin Li AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
161*67e74705SXin Li State.get(), N->getLocationContext(), true);
162*67e74705SXin Li }
163*67e74705SXin Li break;
164*67e74705SXin Li }
165*67e74705SXin Li case Stmt::ObjCIvarRefExprClass: {
166*67e74705SXin Li const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
167*67e74705SXin Li os << "Access to instance variable '" << *IV->getDecl()
168*67e74705SXin Li << "' results in a dereference of a null pointer";
169*67e74705SXin Li AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
170*67e74705SXin Li State.get(), N->getLocationContext(), true);
171*67e74705SXin Li break;
172*67e74705SXin Li }
173*67e74705SXin Li default:
174*67e74705SXin Li break;
175*67e74705SXin Li }
176*67e74705SXin Li
177*67e74705SXin Li auto report = llvm::make_unique<BugReport>(
178*67e74705SXin Li *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
179*67e74705SXin Li
180*67e74705SXin Li bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S), *report);
181*67e74705SXin Li
182*67e74705SXin Li for (SmallVectorImpl<SourceRange>::iterator
183*67e74705SXin Li I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
184*67e74705SXin Li report->addRange(*I);
185*67e74705SXin Li
186*67e74705SXin Li C.emitReport(std::move(report));
187*67e74705SXin Li }
188*67e74705SXin Li
checkLocation(SVal l,bool isLoad,const Stmt * S,CheckerContext & C) const189*67e74705SXin Li void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
190*67e74705SXin Li CheckerContext &C) const {
191*67e74705SXin Li // Check for dereference of an undefined value.
192*67e74705SXin Li if (l.isUndef()) {
193*67e74705SXin Li if (ExplodedNode *N = C.generateErrorNode()) {
194*67e74705SXin Li if (!BT_undef)
195*67e74705SXin Li BT_undef.reset(
196*67e74705SXin Li new BuiltinBug(this, "Dereference of undefined pointer value"));
197*67e74705SXin Li
198*67e74705SXin Li auto report =
199*67e74705SXin Li llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
200*67e74705SXin Li bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S),
201*67e74705SXin Li *report);
202*67e74705SXin Li C.emitReport(std::move(report));
203*67e74705SXin Li }
204*67e74705SXin Li return;
205*67e74705SXin Li }
206*67e74705SXin Li
207*67e74705SXin Li DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
208*67e74705SXin Li
209*67e74705SXin Li // Check for null dereferences.
210*67e74705SXin Li if (!location.getAs<Loc>())
211*67e74705SXin Li return;
212*67e74705SXin Li
213*67e74705SXin Li ProgramStateRef state = C.getState();
214*67e74705SXin Li
215*67e74705SXin Li ProgramStateRef notNullState, nullState;
216*67e74705SXin Li std::tie(notNullState, nullState) = state->assume(location);
217*67e74705SXin Li
218*67e74705SXin Li // The explicit NULL case.
219*67e74705SXin Li if (nullState) {
220*67e74705SXin Li if (!notNullState) {
221*67e74705SXin Li const Expr *expr = getDereferenceExpr(S);
222*67e74705SXin Li if (!suppressReport(expr)) {
223*67e74705SXin Li reportBug(nullState, expr, C);
224*67e74705SXin Li return;
225*67e74705SXin Li }
226*67e74705SXin Li }
227*67e74705SXin Li
228*67e74705SXin Li // Otherwise, we have the case where the location could either be
229*67e74705SXin Li // null or not-null. Record the error node as an "implicit" null
230*67e74705SXin Li // dereference.
231*67e74705SXin Li if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
232*67e74705SXin Li ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
233*67e74705SXin Li /*IsDirectDereference=*/true};
234*67e74705SXin Li dispatchEvent(event);
235*67e74705SXin Li }
236*67e74705SXin Li }
237*67e74705SXin Li
238*67e74705SXin Li // From this point forward, we know that the location is not null.
239*67e74705SXin Li C.addTransition(notNullState);
240*67e74705SXin Li }
241*67e74705SXin Li
checkBind(SVal L,SVal V,const Stmt * S,CheckerContext & C) const242*67e74705SXin Li void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
243*67e74705SXin Li CheckerContext &C) const {
244*67e74705SXin Li // If we're binding to a reference, check if the value is known to be null.
245*67e74705SXin Li if (V.isUndef())
246*67e74705SXin Li return;
247*67e74705SXin Li
248*67e74705SXin Li const MemRegion *MR = L.getAsRegion();
249*67e74705SXin Li const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
250*67e74705SXin Li if (!TVR)
251*67e74705SXin Li return;
252*67e74705SXin Li
253*67e74705SXin Li if (!TVR->getValueType()->isReferenceType())
254*67e74705SXin Li return;
255*67e74705SXin Li
256*67e74705SXin Li ProgramStateRef State = C.getState();
257*67e74705SXin Li
258*67e74705SXin Li ProgramStateRef StNonNull, StNull;
259*67e74705SXin Li std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
260*67e74705SXin Li
261*67e74705SXin Li if (StNull) {
262*67e74705SXin Li if (!StNonNull) {
263*67e74705SXin Li const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
264*67e74705SXin Li if (!suppressReport(expr)) {
265*67e74705SXin Li reportBug(StNull, expr, C);
266*67e74705SXin Li return;
267*67e74705SXin Li }
268*67e74705SXin Li }
269*67e74705SXin Li
270*67e74705SXin Li // At this point the value could be either null or non-null.
271*67e74705SXin Li // Record this as an "implicit" null dereference.
272*67e74705SXin Li if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
273*67e74705SXin Li ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
274*67e74705SXin Li &C.getBugReporter(),
275*67e74705SXin Li /*IsDirectDereference=*/true};
276*67e74705SXin Li dispatchEvent(event);
277*67e74705SXin Li }
278*67e74705SXin Li }
279*67e74705SXin Li
280*67e74705SXin Li // Unlike a regular null dereference, initializing a reference with a
281*67e74705SXin Li // dereferenced null pointer does not actually cause a runtime exception in
282*67e74705SXin Li // Clang's implementation of references.
283*67e74705SXin Li //
284*67e74705SXin Li // int &r = *p; // safe??
285*67e74705SXin Li // if (p != NULL) return; // uh-oh
286*67e74705SXin Li // r = 5; // trap here
287*67e74705SXin Li //
288*67e74705SXin Li // The standard says this is invalid as soon as we try to create a "null
289*67e74705SXin Li // reference" (there is no such thing), but turning this into an assumption
290*67e74705SXin Li // that 'p' is never null will not match our actual runtime behavior.
291*67e74705SXin Li // So we do not record this assumption, allowing us to warn on the last line
292*67e74705SXin Li // of this example.
293*67e74705SXin Li //
294*67e74705SXin Li // We do need to add a transition because we may have generated a sink for
295*67e74705SXin Li // the "implicit" null dereference.
296*67e74705SXin Li C.addTransition(State, this);
297*67e74705SXin Li }
298*67e74705SXin Li
registerDereferenceChecker(CheckerManager & mgr)299*67e74705SXin Li void ento::registerDereferenceChecker(CheckerManager &mgr) {
300*67e74705SXin Li mgr.registerChecker<DereferenceChecker>();
301*67e74705SXin Li }
302