DereferenceChecker.cpp revision e172e8b9e7fc67d7d03589af7e92fe777afcf33a
15c22c8074404797f1313b1334757254fb5c6487aEli Friedman//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
25c22c8074404797f1313b1334757254fb5c6487aEli Friedman//
35c22c8074404797f1313b1334757254fb5c6487aEli Friedman//                     The LLVM Compiler Infrastructure
45c22c8074404797f1313b1334757254fb5c6487aEli Friedman//
55c22c8074404797f1313b1334757254fb5c6487aEli Friedman// This file is distributed under the University of Illinois Open Source
65c22c8074404797f1313b1334757254fb5c6487aEli Friedman// License. See LICENSE.TXT for details.
75c22c8074404797f1313b1334757254fb5c6487aEli Friedman//
85c22c8074404797f1313b1334757254fb5c6487aEli Friedman//===----------------------------------------------------------------------===//
95c22c8074404797f1313b1334757254fb5c6487aEli Friedman//
105c22c8074404797f1313b1334757254fb5c6487aEli Friedman// This defines NullDerefChecker, a builtin check in ExprEngine that performs
115c22c8074404797f1313b1334757254fb5c6487aEli Friedman// checks for null pointers at loads and stores.
125c22c8074404797f1313b1334757254fb5c6487aEli Friedman//
13509150f973ae650a57b79010a3ec36e60e40f41dEli Friedman//===----------------------------------------------------------------------===//
14509150f973ae650a57b79010a3ec36e60e40f41dEli Friedman
155c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "ClangSACheckers.h"
165c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/Checker.h"
175c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/CheckerManager.h"
185c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
195c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
205c22c8074404797f1313b1334757254fb5c6487aEli Friedman
215c22c8074404797f1313b1334757254fb5c6487aEli Friedmanusing namespace clang;
225c22c8074404797f1313b1334757254fb5c6487aEli Friedmanusing namespace ento;
2398ca4f2a325f72374a477f9deba7d09e8999c29bDan Gohman
2498ca4f2a325f72374a477f9deba7d09e8999c29bDan Gohmannamespace {
255c22c8074404797f1313b1334757254fb5c6487aEli Friedmanclass DereferenceChecker
265c22c8074404797f1313b1334757254fb5c6487aEli Friedman    : public Checker< check::Location,
275c22c8074404797f1313b1334757254fb5c6487aEli Friedman                        EventDispatcher<ImplicitNullDerefEvent> > {
285c22c8074404797f1313b1334757254fb5c6487aEli Friedman  mutable llvm::OwningPtr<BuiltinBug> BT_null;
295c22c8074404797f1313b1334757254fb5c6487aEli Friedman  mutable llvm::OwningPtr<BuiltinBug> BT_undef;
305c22c8074404797f1313b1334757254fb5c6487aEli Friedman
315c22c8074404797f1313b1334757254fb5c6487aEli Friedmanpublic:
325c22c8074404797f1313b1334757254fb5c6487aEli Friedman  void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
335c22c8074404797f1313b1334757254fb5c6487aEli Friedman
345c22c8074404797f1313b1334757254fb5c6487aEli Friedman  static void AddDerefSource(raw_ostream &os,
355c22c8074404797f1313b1334757254fb5c6487aEli Friedman                             SmallVectorImpl<SourceRange> &Ranges,
365c22c8074404797f1313b1334757254fb5c6487aEli Friedman                             const Expr *Ex, bool loadedFrom = false);
37d858e90f039f5fcdc2fa93035e911a5a9505cc50Dan Gohman};
385c22c8074404797f1313b1334757254fb5c6487aEli Friedman} // end anonymous namespace
395c22c8074404797f1313b1334757254fb5c6487aEli Friedman
40c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesvoid DereferenceChecker::AddDerefSource(raw_ostream &os,
41c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines                                     SmallVectorImpl<SourceRange> &Ranges,
42c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines                                        const Expr *Ex,
43ea387fc3b8cf12c3c6ad218b81eca156e8173bbaPreston Gurd                                        bool loadedFrom) {
445c22c8074404797f1313b1334757254fb5c6487aEli Friedman  Ex = Ex->IgnoreParenLValueCasts();
45c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  switch (Ex->getStmtClass()) {
465c22c8074404797f1313b1334757254fb5c6487aEli Friedman    default:
475c22c8074404797f1313b1334757254fb5c6487aEli Friedman      return;
485c22c8074404797f1313b1334757254fb5c6487aEli Friedman    case Stmt::DeclRefExprClass: {
495c22c8074404797f1313b1334757254fb5c6487aEli Friedman      const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
505c22c8074404797f1313b1334757254fb5c6487aEli Friedman      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
515c22c8074404797f1313b1334757254fb5c6487aEli Friedman        os << " (" << (loadedFrom ? "loaded from" : "from")
525c22c8074404797f1313b1334757254fb5c6487aEli Friedman           << " variable '" <<  VD->getName() << "')";
53c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        Ranges.push_back(DR->getSourceRange());
545c22c8074404797f1313b1334757254fb5c6487aEli Friedman      }
55c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      return;
56c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    }
575c22c8074404797f1313b1334757254fb5c6487aEli Friedman    case Stmt::MemberExprClass: {
58c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      const MemberExpr *ME = cast<MemberExpr>(Ex);
59c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      os << " (" << (loadedFrom ? "loaded from" : "via")
605c22c8074404797f1313b1334757254fb5c6487aEli Friedman         << " field '" << ME->getMemberNameInfo() << "')";
61c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      SourceLocation L = ME->getMemberLoc();
62c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      Ranges.push_back(SourceRange(L, L));
63c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      break;
64c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    }
65c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  }
66c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines}
67c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
68c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesvoid DereferenceChecker::checkLocation(SVal l, bool isLoad,
69c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines                                       CheckerContext &C) const {
70c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  // Check for dereference of an undefined value.
71c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (l.isUndef()) {
72c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    if (ExplodedNode *N = C.generateSink()) {
7306cc324b9da1dc8fb7360a560343c28f5e7a940aNadav Rotem      if (!BT_undef)
74c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));
75c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
7666de2af815f97e484c1940ff157ffbb809931b20Nadav Rotem      BugReport *report =
77c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        new BugReport(*BT_undef, BT_undef->getDescription(), N);
78c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
79c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines                                bugreporter::GetDerefExpr(N));
80c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      C.EmitReport(report);
81c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    }
82c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    return;
83c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  }
84c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
85c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
86c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
87c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  // Check for null dereferences.
88c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (!isa<Loc>(location))
89c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    return;
90c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
91c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  const Stmt *S = C.getStmt();
92c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  const ProgramState *state = C.getState();
93c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  const ProgramState *notNullState, *nullState;
94c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  llvm::tie(notNullState, nullState) = state->assume(location);
95c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
96c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  // The explicit NULL case.
97c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (nullState) {
98c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    if (!notNullState) {
99dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      // Generate an error node.
100c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      ExplodedNode *N = C.generateSink(nullState);
101c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      if (!N)
102c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        return;
103aec5861bb6ace3734163c000cb75ca2e22e29caaNadav Rotem
104e757f00446fb3c80a96d729f0530b87e9148db7fNadav Rotem      // We know that 'location' cannot be non-null.  This is what
105e9b58d0aac4e89b53a4be0e6f289b66649e1512bNadav Rotem      // we call an "explicit" null dereference.
106e9b58d0aac4e89b53a4be0e6f289b66649e1512bNadav Rotem      if (!BT_null)
1075c22c8074404797f1313b1334757254fb5c6487aEli Friedman        BT_null.reset(new BuiltinBug("Dereference of null pointer"));
108c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
109c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      llvm::SmallString<100> buf;
110c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      SmallVector<SourceRange, 2> Ranges;
111c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
112c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      // Walk through lvalue casts to get the original expression
113c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      // that syntactically caused the load.
114c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      if (const Expr *expr = dyn_cast<Expr>(S))
115c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        S = expr->IgnoreParenLValueCasts();
116c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines
117c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      switch (S->getStmtClass()) {
118c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        case Stmt::ArraySubscriptExprClass: {
119c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          llvm::raw_svector_ostream os(buf);
120c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          os << "Array access";
121c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
122c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
123c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          os << " results in a null pointer dereference";
124c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          break;
125c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        }
126c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines        case Stmt::UnaryOperatorClass: {
127c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines          llvm::raw_svector_ostream os(buf);
1285c22c8074404797f1313b1334757254fb5c6487aEli Friedman          os << "Dereference of null pointer";
1295c22c8074404797f1313b1334757254fb5c6487aEli Friedman          const UnaryOperator *U = cast<UnaryOperator>(S);
1305c22c8074404797f1313b1334757254fb5c6487aEli Friedman          AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
1315c22c8074404797f1313b1334757254fb5c6487aEli Friedman          break;
1325c22c8074404797f1313b1334757254fb5c6487aEli Friedman        }
1335c22c8074404797f1313b1334757254fb5c6487aEli Friedman        case Stmt::MemberExprClass: {
134d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          const MemberExpr *M = cast<MemberExpr>(S);
135d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          if (M->isArrow()) {
136d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem            llvm::raw_svector_ostream os(buf);
13736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines            os << "Access to field '" << M->getMemberNameInfo()
138d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem               << "' results in a dereference of a null pointer";
139d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem            AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
140d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          }
141d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          break;
142d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem        }
143d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem        case Stmt::ObjCIvarRefExprClass: {
144d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
145d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          if (const DeclRefExpr *DR =
146d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem              dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
147d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem            if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
148d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem              llvm::raw_svector_ostream os(buf);
149d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem              os << "Instance variable access (via '" << VD->getName()
150d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem                 << "') results in a null pointer dereference";
151d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem            }
152d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem          }
1535c22c8074404797f1313b1334757254fb5c6487aEli Friedman          Ranges.push_back(IV->getSourceRange());
1545c22c8074404797f1313b1334757254fb5c6487aEli Friedman          break;
1555c22c8074404797f1313b1334757254fb5c6487aEli Friedman        }
1565c22c8074404797f1313b1334757254fb5c6487aEli Friedman        default:
1575c22c8074404797f1313b1334757254fb5c6487aEli Friedman          break;
1585c22c8074404797f1313b1334757254fb5c6487aEli Friedman      }
1595c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1605c22c8074404797f1313b1334757254fb5c6487aEli Friedman      BugReport *report =
16136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines        new BugReport(*BT_null,
1625c22c8074404797f1313b1334757254fb5c6487aEli Friedman                              buf.empty() ? BT_null->getDescription():buf.str(),
1635c22c8074404797f1313b1334757254fb5c6487aEli Friedman                              N);
1645c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1655c22c8074404797f1313b1334757254fb5c6487aEli Friedman      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
1665c22c8074404797f1313b1334757254fb5c6487aEli Friedman                                bugreporter::GetDerefExpr(N));
1675c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1685c22c8074404797f1313b1334757254fb5c6487aEli Friedman      for (SmallVectorImpl<SourceRange>::iterator
1695c22c8074404797f1313b1334757254fb5c6487aEli Friedman            I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
1705c22c8074404797f1313b1334757254fb5c6487aEli Friedman        report->addRange(*I);
1715c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1725c22c8074404797f1313b1334757254fb5c6487aEli Friedman      C.EmitReport(report);
1735c22c8074404797f1313b1334757254fb5c6487aEli Friedman      return;
1745c22c8074404797f1313b1334757254fb5c6487aEli Friedman    }
1755c22c8074404797f1313b1334757254fb5c6487aEli Friedman    else {
1765c22c8074404797f1313b1334757254fb5c6487aEli Friedman      // Otherwise, we have the case where the location could either be
1775c22c8074404797f1313b1334757254fb5c6487aEli Friedman      // null or not-null.  Record the error node as an "implicit" null
1785c22c8074404797f1313b1334757254fb5c6487aEli Friedman      // dereference.
1795c22c8074404797f1313b1334757254fb5c6487aEli Friedman      if (ExplodedNode *N = C.generateSink(nullState)) {
1805c22c8074404797f1313b1334757254fb5c6487aEli Friedman        ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() };
1815c22c8074404797f1313b1334757254fb5c6487aEli Friedman        dispatchEvent(event);
1825c22c8074404797f1313b1334757254fb5c6487aEli Friedman      }
1835c22c8074404797f1313b1334757254fb5c6487aEli Friedman    }
1845c22c8074404797f1313b1334757254fb5c6487aEli Friedman  }
1855c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1865c22c8074404797f1313b1334757254fb5c6487aEli Friedman  // From this point forward, we know that the location is not null.
1875c22c8074404797f1313b1334757254fb5c6487aEli Friedman  C.addTransition(notNullState);
1885c22c8074404797f1313b1334757254fb5c6487aEli Friedman}
1895c22c8074404797f1313b1334757254fb5c6487aEli Friedman
1905c22c8074404797f1313b1334757254fb5c6487aEli Friedmanvoid ento::registerDereferenceChecker(CheckerManager &mgr) {
1915c22c8074404797f1313b1334757254fb5c6487aEli Friedman  mgr.registerChecker<DereferenceChecker>();
1925c22c8074404797f1313b1334757254fb5c6487aEli Friedman}
1935c22c8074404797f1313b1334757254fb5c6487aEli Friedman