DereferenceChecker.cpp revision e576af2754bfa309bb10a518bbc17c81b9e0723f
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//
10bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// This defines NullDerefChecker, a builtin check in GRExprEngine that performs
11bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// checks for null pointers at loads and stores.
12bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//
13bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===//
14bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
15dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
16b4b817d704287836b52b34369009e682f208aa2bTed Kremenek#include "clang/Analysis/PathSensitive/Checker.h"
17bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek#include "clang/Analysis/PathSensitive/GRExprEngine.h"
18bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek#include "clang/Analysis/PathSensitive/BugReporter.h"
19b4b817d704287836b52b34369009e682f208aa2bTed Kremenek#include "GRExprEngineInternalChecks.h"
20bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
21bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenekusing namespace clang;
22bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
23b4b817d704287836b52b34369009e682f208aa2bTed Kremeneknamespace {
24b4b817d704287836b52b34369009e682f208aa2bTed Kremenekclass VISIBILITY_HIDDEN DereferenceChecker : public Checker {
25b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  BuiltinBug *BT_null;
26b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  BuiltinBug *BT_undef;
27b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
28b4b817d704287836b52b34369009e682f208aa2bTed Kremenekpublic:
29b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  DereferenceChecker() : BT_null(0), BT_undef(0) {}
30b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  static void *getTag() { static int tag = 0; return &tag; }
31b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
32bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
33b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  std::pair<ExplodedNode * const*, ExplodedNode * const*>
34b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  getImplicitNodes() const {
35b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return std::make_pair(ImplicitNullDerefNodes.data(),
36b4b817d704287836b52b34369009e682f208aa2bTed Kremenek                          ImplicitNullDerefNodes.data() +
37b4b817d704287836b52b34369009e682f208aa2bTed Kremenek                          ImplicitNullDerefNodes.size());
38bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek  }
39b4b817d704287836b52b34369009e682f208aa2bTed Kremenek};
40b4b817d704287836b52b34369009e682f208aa2bTed Kremenek} // end anonymous namespace
41bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek
42b4b817d704287836b52b34369009e682f208aa2bTed Kremenekvoid clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
43b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  Eng.registerCheck(new DereferenceChecker());
44bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek}
45dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek
46b4b817d704287836b52b34369009e682f208aa2bTed Kremenekstd::pair<ExplodedNode * const *, ExplodedNode * const *>
47b4b817d704287836b52b34369009e682f208aa2bTed Kremenekclang::GetImplicitNullDereferences(GRExprEngine &Eng) {
48b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
49b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (!checker)
50b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return std::make_pair((ExplodedNode * const *) 0,
51b4b817d704287836b52b34369009e682f208aa2bTed Kremenek                          (ExplodedNode * const *) 0);
52b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  return checker->getImplicitNodes();
53dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek}
54dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek
55b4b817d704287836b52b34369009e682f208aa2bTed Kremenekvoid DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
56b4b817d704287836b52b34369009e682f208aa2bTed Kremenek                                       SVal l) {
57b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // Check for dereference of an undefined value.
58b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (l.isUndef()) {
5919d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek    if (ExplodedNode *N = C.GenerateSink()) {
60b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      if (!BT_undef)
61b4b817d704287836b52b34369009e682f208aa2bTed Kremenek        BT_undef = new BuiltinBug("Dereference of undefined pointer value");
62b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
63b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      EnhancedBugReport *report =
64d02e232c43b979758810794de24d3f5cde40fe93Benjamin Kramer        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
65b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
66b4b817d704287836b52b34369009e682f208aa2bTed Kremenek                                bugreporter::GetDerefExpr(N));
67b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      C.EmitReport(report);
68b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    }
69b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return;
70b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  }
71b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
72b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
73b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
74b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // Check for null dereferences.
75b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (!isa<Loc>(location))
76b4b817d704287836b52b34369009e682f208aa2bTed Kremenek    return;
77b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
78b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  const GRState *state = C.getState();
79b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  const GRState *notNullState, *nullState;
80b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  llvm::tie(notNullState, nullState) = state->Assume(location);
81b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
82b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // The explicit NULL case.
83b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  if (nullState) {
8478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek    if (!notNullState) {
8578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // Generate an error node.
8619d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek      ExplodedNode *N = C.GenerateSink(nullState);
8778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      if (!N)
88b4b817d704287836b52b34369009e682f208aa2bTed Kremenek        return;
8978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek
9078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // We know that 'location' cannot be non-null.  This is what
9178d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // we call an "explicit" null dereference.
9278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      if (!BT_null)
93e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        BT_null = new BuiltinBug("Dereference of null pointer");
94e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek
95e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      llvm::SmallString<100> buf;
96e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek
97e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      switch (S->getStmtClass()) {
98e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        case Stmt::UnaryOperatorClass: {
99e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          const UnaryOperator *U = cast<UnaryOperator>(S);
100e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          const Expr *SU = U->getSubExpr()->IgnoreParens();
101e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
102e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek            if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
103e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek              llvm::raw_svector_ostream os(buf);
104e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek              os << "Dereference of null pointer loaded from variable '"
105e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek                 << VD->getName() << '\'';
106e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek            }
107e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          }
108e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        }
109e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        default:
110e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek          break;
111e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek      }
112dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek
11378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      EnhancedBugReport *report =
114e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek        new EnhancedBugReport(*BT_null,
115e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek                              buf.empty() ? BT_null->getDescription():buf.str(),
116e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek                              N);
117e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek
11878d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
11978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek                                bugreporter::GetDerefExpr(N));
12078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek
12178d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      C.EmitReport(report);
12278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      return;
12378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek    }
12478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek    else {
125b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      // Otherwise, we have the case where the location could either be
126b4b817d704287836b52b34369009e682f208aa2bTed Kremenek      // null or not-null.  Record the error node as an "implicit" null
12778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek      // dereference.
12819d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek      if (ExplodedNode *N = C.GenerateSink(nullState))
12978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek        ImplicitNullDerefNodes.push_back(N);
130dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek    }
131dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek  }
132b4b817d704287836b52b34369009e682f208aa2bTed Kremenek
133b4b817d704287836b52b34369009e682f208aa2bTed Kremenek  // From this point forward, we know that the location is not null.
13419d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek  C.addTransition(notNullState);
135dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek}
136