blob: 5be12783bd8c08178e4585a651920dd2694240bf [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 "GRExprEngineInternalChecks.h"
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000016#include "clang/GR/BugReporter/BugType.h"
17#include "clang/GR/PathSensitive/CheckerVisitor.h"
Zhongxing Xu94943b62009-11-03 07:35:33 +000018
19using namespace clang;
20
Ted Kremenekf493f492009-11-11 05:50:44 +000021namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000022class AttrNonNullChecker
Ted Kremenekf493f492009-11-11 05:50:44 +000023 : 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();
Zhongxing Xu94943b62009-11-03 07:35:33 +000042
43 // Check if the callee has a 'nonnull' attribute.
Ted Kremenek13976632010-02-08 16:18:51 +000044 SVal X = state->getSVal(CE->getCallee());
Zhongxing Xu94943b62009-11-03 07:35:33 +000045
46 const FunctionDecl* FD = X.getAsFunctionDecl();
47 if (!FD)
48 return;
49
50 const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
51 if (!Att)
52 return;
53
54 // Iterate through the arguments of CE and check them for null.
55 unsigned idx = 0;
56
57 for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
58 ++I, ++idx) {
59
60 if (!Att->isNonNull(idx))
61 continue;
62
Jordy Rose9a126852010-06-21 20:08:28 +000063 SVal V = state->getSVal(*I);
64 DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
65
66 // If the value is unknown or undefined, we can't perform this check.
67 if (!DV)
68 continue;
Zhongxing Xu94943b62009-11-03 07:35:33 +000069
Ted Kremenekbb0ba0b2010-11-09 02:11:43 +000070 if (!isa<Loc>(*DV)) {
71 // If the argument is a union type, we want to handle a potential
72 // transparent_unoin GCC extension.
73 QualType T = (*I)->getType();
74 const RecordType *UT = T->getAsUnionType();
75 if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
76 continue;
77 if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
78 nonloc::CompoundVal::iterator CSV_I = CSV->begin();
79 assert(CSV_I != CSV->end());
80 V = *CSV_I;
81 DV = dyn_cast<DefinedSVal>(&V);
82 assert(++CSV_I == CSV->end());
83 if (!DV)
84 continue;
85 }
86 else {
87 // FIXME: Handle LazyCompoundVals?
88 continue;
89 }
90 }
91
Zhongxing Xu94943b62009-11-03 07:35:33 +000092 ConstraintManager &CM = C.getConstraintManager();
93 const GRState *stateNotNull, *stateNull;
Ted Kremenek28f47b92010-12-01 22:16:56 +000094 llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
Zhongxing Xu94943b62009-11-03 07:35:33 +000095
96 if (stateNull && !stateNotNull) {
97 // Generate an error node. Check for a null node in case
98 // we cache out.
Ted Kremenekd048c6e2010-12-20 21:19:09 +000099 if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
Zhongxing Xu94943b62009-11-03 07:35:33 +0000100
101 // Lazily allocate the BugType object if it hasn't already been
102 // created. Ownership is transferred to the BugReporter object once
103 // the BugReport is passed to 'EmitWarning'.
104 if (!BT)
105 BT = new BugType("Argument with 'nonnull' attribute passed null",
106 "API");
107
108 EnhancedBugReport *R =
109 new EnhancedBugReport(*BT,
110 "Null pointer passed as an argument to a "
111 "'nonnull' parameter", errorNode);
112
113 // Highlight the range of the argument that was null.
114 const Expr *arg = *I;
115 R->addRange(arg->getSourceRange());
116 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
117
118 // Emit the bug report.
119 C.EmitReport(R);
120 }
121
122 // Always return. Either we cached out or we just emitted an error.
123 return;
124 }
125
126 // If a pointer value passed the check we should assume that it is
127 // indeed not null from this point forward.
128 assert(stateNotNull);
129 state = stateNotNull;
130 }
131
132 // If we reach here all of the arguments passed the nonnull check.
133 // If 'state' has been updated generated a new node.
Ted Kremenek19d67b52009-11-23 22:22:01 +0000134 C.addTransition(state);
Zhongxing Xu94943b62009-11-03 07:35:33 +0000135}