xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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