blob: 646b30bc3153e5e68da8a8c2f7ebd15ff138e75d [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//
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000010// This defines AttrNonNullChecker, a builtin check in ExprEngine that
Zhongxing Xu94943b62009-11-03 07:35:33 +000011// performs checks for arguments declared to have nonnull attribute.
12//
13//===----------------------------------------------------------------------===//
14
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000015#include "ExprEngineInternalChecks.h"
Ted Kremenek21142582010-12-23 19:38:26 +000016#include "clang/StaticAnalyzer/BugReporter/BugType.h"
17#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
Zhongxing Xu94943b62009-11-03 07:35:33 +000018
19using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000020using namespace ento;
Zhongxing Xu94943b62009-11-03 07:35:33 +000021
Ted Kremenekf493f492009-11-11 05:50:44 +000022namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000023class AttrNonNullChecker
Ted Kremenekf493f492009-11-11 05:50:44 +000024 : public CheckerVisitor<AttrNonNullChecker> {
25 BugType *BT;
26public:
27 AttrNonNullChecker() : BT(0) {}
28 static void *getTag() {
29 static int x = 0;
30 return &x;
31 }
32 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
33};
34} // end anonymous namespace
35
Ted Kremenek9ef65372010-12-23 07:20:52 +000036void ento::RegisterAttrNonNullChecker(ExprEngine &Eng) {
Ted Kremenekf493f492009-11-11 05:50:44 +000037 Eng.registerCheck(new AttrNonNullChecker());
Zhongxing Xu94943b62009-11-03 07:35:33 +000038}
39
40void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
41 const CallExpr *CE) {
42 const GRState *state = C.getState();
Zhongxing Xu94943b62009-11-03 07:35:33 +000043
44 // Check if the callee has a 'nonnull' attribute.
Ted Kremenek13976632010-02-08 16:18:51 +000045 SVal X = state->getSVal(CE->getCallee());
Zhongxing Xu94943b62009-11-03 07:35:33 +000046
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
Jordy Rose9a126852010-06-21 20:08:28 +000064 SVal V = state->getSVal(*I);
65 DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
66
67 // If the value is unknown or undefined, we can't perform this check.
68 if (!DV)
69 continue;
Zhongxing Xu94943b62009-11-03 07:35:33 +000070
Ted Kremenekbb0ba0b2010-11-09 02:11:43 +000071 if (!isa<Loc>(*DV)) {
72 // If the argument is a union type, we want to handle a potential
73 // transparent_unoin GCC extension.
74 QualType T = (*I)->getType();
75 const RecordType *UT = T->getAsUnionType();
76 if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
77 continue;
78 if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
79 nonloc::CompoundVal::iterator CSV_I = CSV->begin();
80 assert(CSV_I != CSV->end());
81 V = *CSV_I;
82 DV = dyn_cast<DefinedSVal>(&V);
83 assert(++CSV_I == CSV->end());
84 if (!DV)
85 continue;
86 }
87 else {
88 // FIXME: Handle LazyCompoundVals?
89 continue;
90 }
91 }
92
Zhongxing Xu94943b62009-11-03 07:35:33 +000093 ConstraintManager &CM = C.getConstraintManager();
94 const GRState *stateNotNull, *stateNull;
Ted Kremenek28f47b92010-12-01 22:16:56 +000095 llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
Zhongxing Xu94943b62009-11-03 07:35:33 +000096
97 if (stateNull && !stateNotNull) {
98 // Generate an error node. Check for a null node in case
99 // we cache out.
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000100 if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
Zhongxing Xu94943b62009-11-03 07:35:33 +0000101
102 // Lazily allocate the BugType object if it hasn't already been
103 // created. Ownership is transferred to the BugReporter object once
104 // the BugReport is passed to 'EmitWarning'.
105 if (!BT)
106 BT = new BugType("Argument with 'nonnull' attribute passed null",
107 "API");
108
109 EnhancedBugReport *R =
110 new EnhancedBugReport(*BT,
111 "Null pointer passed as an argument to a "
112 "'nonnull' parameter", errorNode);
113
114 // Highlight the range of the argument that was null.
115 const Expr *arg = *I;
116 R->addRange(arg->getSourceRange());
117 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
118
119 // Emit the bug report.
120 C.EmitReport(R);
121 }
122
123 // Always return. Either we cached out or we just emitted an error.
124 return;
125 }
126
127 // If a pointer value passed the check we should assume that it is
128 // indeed not null from this point forward.
129 assert(stateNotNull);
130 state = stateNotNull;
131 }
132
133 // If we reach here all of the arguments passed the nonnull check.
134 // If 'state' has been updated generated a new node.
Ted Kremenek19d67b52009-11-23 22:22:01 +0000135 C.addTransition(state);
Zhongxing Xu94943b62009-11-03 07:35:33 +0000136}