 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
67.6% |
23 / 34 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
94.1% |
32 / 34 |
| |
|
Line Coverage: |
97.9% |
47 / 48 |
| |
 |
|
 |
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.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "clang/Checker/Checkers/DereferenceChecker.h"
16 : #include "clang/Checker/PathSensitive/Checker.h"
17 : #include "clang/Checker/PathSensitive/GRExprEngine.h"
18 : #include "clang/Checker/BugReporter/BugReporter.h"
19 : #include "GRExprEngineInternalChecks.h"
20 :
21 : using namespace clang;
22 :
23 : namespace {
2138: branch 2 taken
0: branch 3 not taken
0: branch 7 not taken
0: branch 8 not taken
24 2138: class DereferenceChecker : public Checker {
25 : BuiltinBug *BT_null;
26 : BuiltinBug *BT_undef;
27 : llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
28 : public:
29 2138: DereferenceChecker() : BT_null(0), BT_undef(0) {}
30 2162: static void *getTag() { static int tag = 0; return &tag; }
31 : void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
32 :
33 : std::pair<ExplodedNode * const*, ExplodedNode * const*>
34 24: getImplicitNodes() const {
35 : return std::make_pair(ImplicitNullDerefNodes.data(),
36 : ImplicitNullDerefNodes.data() +
37 24: ImplicitNullDerefNodes.size());
38 : }
39 : };
40 : } // end anonymous namespace
41 :
42 2138: void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
43 2138: Eng.registerCheck(new DereferenceChecker());
44 2138: }
45 :
46 : std::pair<ExplodedNode * const *, ExplodedNode * const *>
47 24: clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
48 24: DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
0: branch 0 not taken
24: branch 1 taken
49 24: if (!checker)
50 : return std::make_pair((ExplodedNode * const *) 0,
51 0: (ExplodedNode * const *) 0);
52 24: return checker->getImplicitNodes();
53 : }
54 :
55 : void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
56 10159: SVal l) {
57 : // Check for dereference of an undefined value.
10: branch 1 taken
10149: branch 2 taken
58 10159: if (l.isUndef()) {
10: branch 1 taken
0: branch 2 not taken
59 10: if (ExplodedNode *N = C.GenerateSink()) {
10: branch 0 taken
0: branch 1 not taken
60 10: if (!BT_undef)
61 10: BT_undef = new BuiltinBug("Dereference of undefined pointer value");
62 :
63 : EnhancedBugReport *report =
64 10: new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
65 : report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
66 10: bugreporter::GetDerefExpr(N));
67 10: C.EmitReport(report);
68 : }
69 10: return;
70 : }
71 :
72 10149: DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
73 :
74 : // Check for null dereferences.
0: branch 1 not taken
10149: branch 2 taken
75 10149: if (!isa<Loc>(location))
76 74: return;
77 :
78 10149: const GRState *state = C.getState();
79 : const GRState *notNullState, *nullState;
80 10149: llvm::tie(notNullState, nullState) = state->Assume(location);
81 :
82 : // The explicit NULL case.
392: branch 0 taken
9757: branch 1 taken
83 10149: if (nullState) {
74: branch 0 taken
318: branch 1 taken
84 392: if (!notNullState) {
85 : // Generate an error node.
86 74: ExplodedNode *N = C.GenerateSink(nullState);
0: branch 0 not taken
74: branch 1 taken
87 74: if (!N)
88 : return;
89 :
90 : // We know that 'location' cannot be non-null. This is what
91 : // we call an "explicit" null dereference.
74: branch 0 taken
0: branch 1 not taken
92 74: if (!BT_null)
93 74: BT_null = new BuiltinBug("Dereference of null pointer");
94 :
95 74: llvm::SmallString<100> buf;
96 :
60: branch 1 taken
14: branch 2 taken
97 74: switch (S->getStmtClass()) {
98 : case Stmt::UnaryOperatorClass: {
99 60: const UnaryOperator *U = cast<UnaryOperator>(S);
100 60: const Expr *SU = U->getSubExpr()->IgnoreParens();
59: branch 1 taken
1: branch 2 taken
101 60: if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
59: branch 2 taken
0: branch 3 not taken
102 59: if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
103 59: llvm::raw_svector_ostream os(buf);
104 : os << "Dereference of null pointer loaded from variable '"
105 59: << VD->getName() << '\'';
106 : }
107 : }
108 : }
109 : default:
110 : break;
111 : }
112 :
113 : EnhancedBugReport *report =
114 : new EnhancedBugReport(*BT_null,
115 : buf.empty() ? BT_null->getDescription():buf.str(),
15: branch 1 taken
59: branch 2 taken
116 74: N);
117 :
118 : report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
119 74: bugreporter::GetDerefExpr(N));
120 :
121 74: C.EmitReport(report);
122 74: return;
123 : }
124 : else {
125 : // Otherwise, we have the case where the location could either be
126 : // null or not-null. Record the error node as an "implicit" null
127 : // dereference.
318: branch 1 taken
0: branch 2 not taken
128 318: if (ExplodedNode *N = C.GenerateSink(nullState))
129 318: ImplicitNullDerefNodes.push_back(N);
130 : }
131 : }
132 :
133 : // From this point forward, we know that the location is not null.
10075: branch 2 taken
74: branch 3 taken
134 10075: C.addTransition(notNullState);
135 : }
Generated: 2010-02-10 01:31 by zcov