[analyzer] Refactoring: include/clang/Checker -> include/clang/GR
[clang.git] / lib / Checker / DereferenceChecker.cpp
blob72c88b1a3c7ba1676a4f0597f1668056d73bbf96
1 //== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This defines NullDerefChecker, a builtin check in GRExprEngine that performs
11 // checks for null pointers at loads and stores.
13 //===----------------------------------------------------------------------===//
15 #include "GRExprEngineInternalChecks.h"
16 #include "clang/GR/BugReporter/BugType.h"
17 #include "clang/GR/Checkers/DereferenceChecker.h"
18 #include "clang/GR/PathSensitive/Checker.h"
19 #include "clang/GR/PathSensitive/GRExprEngine.h"
21 using namespace clang;
23 namespace {
24 class DereferenceChecker : public Checker {
25 BuiltinBug *BT_null;
26 BuiltinBug *BT_undef;
27 llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
28 public:
29 DereferenceChecker() : BT_null(0), BT_undef(0) {}
30 static void *getTag() { static int tag = 0; return &tag; }
31 void visitLocation(CheckerContext &C, const Stmt *S, SVal location);
33 std::pair<ExplodedNode * const*, ExplodedNode * const*>
34 getImplicitNodes() const {
35 return std::make_pair(ImplicitNullDerefNodes.data(),
36 ImplicitNullDerefNodes.data() +
37 ImplicitNullDerefNodes.size());
39 void AddDerefSource(llvm::raw_ostream &os,
40 llvm::SmallVectorImpl<SourceRange> &Ranges,
41 const Expr *Ex, bool loadedFrom = false);
43 } // end anonymous namespace
45 void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
46 Eng.registerCheck(new DereferenceChecker());
49 std::pair<ExplodedNode * const *, ExplodedNode * const *>
50 clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
51 DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
52 if (!checker)
53 return std::make_pair((ExplodedNode * const *) 0,
54 (ExplodedNode * const *) 0);
55 return checker->getImplicitNodes();
58 void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
59 llvm::SmallVectorImpl<SourceRange> &Ranges,
60 const Expr *Ex,
61 bool loadedFrom) {
62 Ex = Ex->IgnoreParenLValueCasts();
63 switch (Ex->getStmtClass()) {
64 default:
65 return;
66 case Stmt::DeclRefExprClass: {
67 const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
68 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
69 os << " (" << (loadedFrom ? "loaded from" : "from")
70 << " variable '" << VD->getName() << "')";
71 Ranges.push_back(DR->getSourceRange());
73 return;
75 case Stmt::MemberExprClass: {
76 const MemberExpr *ME = cast<MemberExpr>(Ex);
77 os << " (" << (loadedFrom ? "loaded from" : "via")
78 << " field '" << ME->getMemberNameInfo() << "')";
79 SourceLocation L = ME->getMemberLoc();
80 Ranges.push_back(SourceRange(L, L));
81 break;
86 void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
87 SVal l) {
88 // Check for dereference of an undefined value.
89 if (l.isUndef()) {
90 if (ExplodedNode *N = C.generateSink()) {
91 if (!BT_undef)
92 BT_undef = new BuiltinBug("Dereference of undefined pointer value");
94 EnhancedBugReport *report =
95 new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
96 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
97 bugreporter::GetDerefExpr(N));
98 C.EmitReport(report);
100 return;
103 DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
105 // Check for null dereferences.
106 if (!isa<Loc>(location))
107 return;
109 const GRState *state = C.getState();
110 const GRState *notNullState, *nullState;
111 llvm::tie(notNullState, nullState) = state->assume(location);
113 // The explicit NULL case.
114 if (nullState) {
115 if (!notNullState) {
116 // Generate an error node.
117 ExplodedNode *N = C.generateSink(nullState);
118 if (!N)
119 return;
121 // We know that 'location' cannot be non-null. This is what
122 // we call an "explicit" null dereference.
123 if (!BT_null)
124 BT_null = new BuiltinBug("Dereference of null pointer");
126 llvm::SmallString<100> buf;
127 llvm::SmallVector<SourceRange, 2> Ranges;
129 // Walk through lvalue casts to get the original expression
130 // that syntactically caused the load.
131 if (const Expr *expr = dyn_cast<Expr>(S))
132 S = expr->IgnoreParenLValueCasts();
134 switch (S->getStmtClass()) {
135 case Stmt::ArraySubscriptExprClass: {
136 llvm::raw_svector_ostream os(buf);
137 os << "Array access";
138 const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
139 AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
140 os << " results in a null pointer dereference";
141 break;
143 case Stmt::UnaryOperatorClass: {
144 llvm::raw_svector_ostream os(buf);
145 os << "Dereference of null pointer";
146 const UnaryOperator *U = cast<UnaryOperator>(S);
147 AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
148 break;
150 case Stmt::MemberExprClass: {
151 const MemberExpr *M = cast<MemberExpr>(S);
152 if (M->isArrow()) {
153 llvm::raw_svector_ostream os(buf);
154 os << "Access to field '" << M->getMemberNameInfo()
155 << "' results in a dereference of a null pointer";
156 AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
158 break;
160 case Stmt::ObjCIvarRefExprClass: {
161 const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
162 if (const DeclRefExpr *DR =
163 dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
164 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
165 llvm::raw_svector_ostream os(buf);
166 os << "Instance variable access (via '" << VD->getName()
167 << "') results in a null pointer dereference";
170 Ranges.push_back(IV->getSourceRange());
171 break;
173 default:
174 break;
177 EnhancedBugReport *report =
178 new EnhancedBugReport(*BT_null,
179 buf.empty() ? BT_null->getDescription():buf.str(),
182 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
183 bugreporter::GetDerefExpr(N));
185 for (llvm::SmallVectorImpl<SourceRange>::iterator
186 I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
187 report->addRange(*I);
189 C.EmitReport(report);
190 return;
192 else {
193 // Otherwise, we have the case where the location could either be
194 // null or not-null. Record the error node as an "implicit" null
195 // dereference.
196 if (ExplodedNode *N = C.generateSink(nullState))
197 ImplicitNullDerefNodes.push_back(N);
201 // From this point forward, we know that the location is not null.
202 C.addTransition(notNullState);