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