blob: d0bccb27b4059fbad23a46acc59766bd549b75a4 [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"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000016#include "clang/Checker/BugReporter/BugType.h"
17#include "clang/Checker/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
70 ConstraintManager &CM = C.getConstraintManager();
71 const GRState *stateNotNull, *stateNull;
Jordy Rose9a126852010-06-21 20:08:28 +000072 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
Zhongxing Xu94943b62009-11-03 07:35:33 +000073
74 if (stateNull && !stateNotNull) {
75 // Generate an error node. Check for a null node in case
76 // we cache out.
Ted Kremenek19d67b52009-11-23 22:22:01 +000077 if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) {
Zhongxing Xu94943b62009-11-03 07:35:33 +000078
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.
Ted Kremenek19d67b52009-11-23 22:22:01 +0000112 C.addTransition(state);
Zhongxing Xu94943b62009-11-03 07:35:33 +0000113}