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