blob: 1cf5d0c4af2d4aa4494c0bec4ca31a4755ab6cd7 [file] [log] [blame]
Zhongxing Xu94943b62009-11-03 07:35:33 +00001//===--- AttrNonNullChecker.h - Undefined arguments 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 AttrNonNullChecker, a builtin check in GRExprEngine that
11// performs checks for arguments declared to have nonnull attribute.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
16#include "clang/Analysis/PathSensitive/BugReporter.h"
17
18using namespace clang;
19
20void *AttrNonNullChecker::getTag() {
21 static int x = 0;
22 return &x;
23}
24
25void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
26 const CallExpr *CE) {
27 const GRState *state = C.getState();
28 const GRState *originalState = state;
29
30 // Check if the callee has a 'nonnull' attribute.
31 SVal X = state->getSVal(CE->getCallee());
32
33 const FunctionDecl* FD = X.getAsFunctionDecl();
34 if (!FD)
35 return;
36
37 const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
38 if (!Att)
39 return;
40
41 // Iterate through the arguments of CE and check them for null.
42 unsigned idx = 0;
43
44 for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
45 ++I, ++idx) {
46
47 if (!Att->isNonNull(idx))
48 continue;
49
50 const SVal &V = state->getSVal(*I);
51 const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
52
53 if (!DV)
54 continue;
55
56 ConstraintManager &CM = C.getConstraintManager();
57 const GRState *stateNotNull, *stateNull;
58 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
59
60 if (stateNull && !stateNotNull) {
61 // Generate an error node. Check for a null node in case
62 // we cache out.
63 if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
64
65 // Lazily allocate the BugType object if it hasn't already been
66 // created. Ownership is transferred to the BugReporter object once
67 // the BugReport is passed to 'EmitWarning'.
68 if (!BT)
69 BT = new BugType("Argument with 'nonnull' attribute passed null",
70 "API");
71
72 EnhancedBugReport *R =
73 new EnhancedBugReport(*BT,
74 "Null pointer passed as an argument to a "
75 "'nonnull' parameter", errorNode);
76
77 // Highlight the range of the argument that was null.
78 const Expr *arg = *I;
79 R->addRange(arg->getSourceRange());
80 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
81
82 // Emit the bug report.
83 C.EmitReport(R);
84 }
85
86 // Always return. Either we cached out or we just emitted an error.
87 return;
88 }
89
90 // If a pointer value passed the check we should assume that it is
91 // indeed not null from this point forward.
92 assert(stateNotNull);
93 state = stateNotNull;
94 }
95
96 // If we reach here all of the arguments passed the nonnull check.
97 // If 'state' has been updated generated a new node.
98 if (state != originalState)
99 C.addTransition(C.GenerateNode(CE, state));
100}