DereferenceChecker.cpp revision c35fb7d67d515659ad2325b4f6ec97c9fe64fb63
1bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
2bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
3bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//                     The LLVM Compiler Infrastructure
4bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
5bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// This file is distributed under the University of Illinois Open Source
6bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// License. See LICENSE.TXT for details.
7bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
8bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===//
9bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
10d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis// This defines NullDerefChecker, a builtin check in ExprEngine that performs
11bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// checks for null pointers at loads and stores.
12bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
13bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===//
14bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
15b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "ClangSACheckers.h"
16c35fb7d67d515659ad2325b4f6ec97c9fe64fb63Benjamin Kramer#include "clang/AST/ExprObjC.h"
17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
18b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
22bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenekusing namespace clang;
239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
24bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
25b4b817d704287836b52b34369009e682f208aa2bTed Kremeneknamespace {
26b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisclass DereferenceChecker
27ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis    : public Checker< check::Location,
28b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis                        EventDispatcher<ImplicitNullDerefEvent> > {
29b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis  mutable llvm::OwningPtr<BuiltinBug> BT_null;
30b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis  mutable llvm::OwningPtr<BuiltinBug> BT_undef;
31b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis
32b4b817d704287836b52b34369009e682f208aa2bTed Kremenekpublic:
33390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks  void checkLocation(SVal location, bool isLoad, const Stmt* S,
34390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks                     CheckerContext &C) const;
35b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis
365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  static void AddDerefSource(raw_ostream &os,
375f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                             SmallVectorImpl<SourceRange> &Ranges,
38b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis                             const Expr *Ex, bool loadedFrom = false);
39b4b817d704287836b52b34369009e682f208aa2bTed Kremenek};
40b4b817d704287836b52b34369009e682f208aa2bTed Kremenek} // end anonymous namespace
41bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
425f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnervoid DereferenceChecker::AddDerefSource(raw_ostream &os,
43390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks                                        SmallVectorImpl<SourceRange> &Ranges,
44646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek                                        const Expr *Ex,
45646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek                                        bool loadedFrom) {
46f6a1648197562e0b133440d612d9af297d0a86ccJohn McCall  Ex = Ex->IgnoreParenLValueCasts();
47646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek  switch (Ex->getStmtClass()) {
48646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek    default:
49646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      return;
50646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek    case Stmt::DeclRefExprClass: {
51646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
52646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
53646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek        os << " (" << (loadedFrom ? "loaded from" : "from")
54646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek           << " variable '" <<  VD->getName() << "')";
55646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek        Ranges.push_back(DR->getSourceRange());
56646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      }
57646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      return;
58646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek    }
59646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek    case Stmt::MemberExprClass: {
60646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      const MemberExpr *ME = cast<MemberExpr>(Ex);
61646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      os << " (" << (loadedFrom ? "loaded from" : "via")
62646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek         << " field '" << ME->getMemberNameInfo() << "')";
63646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      SourceLocation L = ME->getMemberLoc();
64646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      Ranges.push_back(SourceRange(L, L));
65646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek      break;
66646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek    }
67646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek  }
68646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek}
69646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek
70390909c89c98ab1807e15e033a72e975f866fb23Anna Zaksvoid DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
71b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis                                       CheckerContext &C) const {
72b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // Check for dereference of an undefined value.
73b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (l.isUndef()) {
74d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek    if (ExplodedNode *N = C.generateSink()) {
75b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      if (!BT_undef)
76b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis        BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));
77452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
78e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks      BugReport *report =
79e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks        new BugReport(*BT_undef, BT_undef->getDescription(), N);
8050bbc165b063155cc23c360deb7b865502e068e2Anna Zaks      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
8150bbc165b063155cc23c360deb7b865502e068e2Anna Zaks                                        bugreporter::GetDerefExpr(N)));
82b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      C.EmitReport(report);
83b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    }
84b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return;
85b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  }
86452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
87b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
88452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
89452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek  // Check for null dereferences.
90b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (!isa<Loc>(location))
91b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return;
92452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
938bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
948bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef notNullState, nullState;
9528f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek  llvm::tie(notNullState, nullState) = state->assume(location);
96452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
97b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // The explicit NULL case.
98b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (nullState) {
99452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek    if (!notNullState) {
10078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // Generate an error node.
101d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek      ExplodedNode *N = C.generateSink(nullState);
10278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      if (!N)
103b4b817d704287836b52b34369009e682f208aa2bTed Kremenek        return;
104452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
10578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // We know that 'location' cannot be non-null.  This is what
106452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek      // we call an "explicit" null dereference.
10778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      if (!BT_null)
108b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis        BT_null.reset(new BuiltinBug("Dereference of null pointer"));
109452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
110e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      llvm::SmallString<100> buf;
1115f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner      SmallVector<SourceRange, 2> Ranges;
112892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek
113892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek      // Walk through lvalue casts to get the original expression
114892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek      // that syntactically caused the load.
115892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek      if (const Expr *expr = dyn_cast<Expr>(S))
116892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek        S = expr->IgnoreParenLValueCasts();
117e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek
118e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      switch (S->getStmtClass()) {
119646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek        case Stmt::ArraySubscriptExprClass: {
120646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          llvm::raw_svector_ostream os(buf);
121646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          os << "Array access";
122646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
123646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
124646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          os << " results in a null pointer dereference";
125646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          break;
126646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek        }
127e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        case Stmt::UnaryOperatorClass: {
128646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          llvm::raw_svector_ostream os(buf);
129646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          os << "Dereference of null pointer";
130e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          const UnaryOperator *U = cast<UnaryOperator>(S);
131646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
132452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek          break;
133452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek        }
134452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek        case Stmt::MemberExprClass: {
135452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek          const MemberExpr *M = cast<MemberExpr>(S);
136646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          if (M->isArrow()) {
137646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek            llvm::raw_svector_ostream os(buf);
138646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek            os << "Access to field '" << M->getMemberNameInfo()
139646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek               << "' results in a dereference of a null pointer";
140646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek            AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
141646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek          }
142452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek          break;
143e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        }
1440853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek        case Stmt::ObjCIvarRefExprClass: {
1450853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek          const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
1460853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek          if (const DeclRefExpr *DR =
1470853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek              dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
1480853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek            if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
1490853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek              llvm::raw_svector_ostream os(buf);
1500853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek              os << "Instance variable access (via '" << VD->getName()
1510853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek                 << "') results in a null pointer dereference";
1520853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek            }
1530853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek          }
1540853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek          Ranges.push_back(IV->getSourceRange());
1550853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek          break;
1560853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek        }
157e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        default:
158e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          break;
159e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      }
160dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek
161e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks      BugReport *report =
162e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks        new BugReport(*BT_null,
163e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek                              buf.empty() ? BT_null->getDescription():buf.str(),
164e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek                              N);
165e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek
16650bbc165b063155cc23c360deb7b865502e068e2Anna Zaks      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
16750bbc165b063155cc23c360deb7b865502e068e2Anna Zaks                                        bugreporter::GetDerefExpr(N)));
168452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
1695f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner      for (SmallVectorImpl<SourceRange>::iterator
170452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek            I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
171452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek        report->addRange(*I);
172452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
17378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      C.EmitReport(report);
17478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      return;
17578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek    }
17678d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek    else {
177b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      // Otherwise, we have the case where the location could either be
178b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      // null or not-null.  Record the error node as an "implicit" null
179452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek      // dereference.
180b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis      if (ExplodedNode *N = C.generateSink(nullState)) {
181b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis        ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() };
182b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis        dispatchEvent(event);
183b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis      }
184dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek    }
185dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek  }
186452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek
187b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // From this point forward, we know that the location is not null.
1880bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks  C.addTransition(notNullState);
189dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek}
190b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis
191b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisvoid ento::registerDereferenceChecker(CheckerManager &mgr) {
192b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis  mgr.registerChecker<DereferenceChecker>();
193b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis}
194