blob: ebc3a4fd5605245dfe57d1973662cf0954694169 [file] [log] [blame]
Zhongxing Xud02174c2009-11-24 04:45:44 +00001//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
Zhongxing Xu8958fff2009-11-03 06:46:03 +00002//
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//
Zhongxing Xud02174c2009-11-24 04:45:44 +000010// This defines CallAndMessageChecker, a builtin checker that checks for various
11// errors of call and objc message expressions.
Zhongxing Xu8958fff2009-11-03 06:46:03 +000012//
13//===----------------------------------------------------------------------===//
14
Ted Kremenekf493f492009-11-11 05:50:44 +000015#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
Zhongxing Xu8958fff2009-11-03 06:46:03 +000016#include "clang/Analysis/PathSensitive/BugReporter.h"
Zhongxing Xu2055eff2009-11-24 07:06:39 +000017#include "clang/AST/ParentMap.h"
Ted Kremenekf493f492009-11-11 05:50:44 +000018#include "GRExprEngineInternalChecks.h"
Zhongxing Xu8958fff2009-11-03 06:46:03 +000019
20using namespace clang;
21
Ted Kremenekf493f492009-11-11 05:50:44 +000022namespace {
Zhongxing Xud02174c2009-11-24 04:45:44 +000023class VISIBILITY_HIDDEN CallAndMessageChecker
24 : public CheckerVisitor<CallAndMessageChecker> {
Ted Kremenekc79d7d42009-11-21 01:25:37 +000025 BugType *BT_call_null;
26 BugType *BT_call_undef;
27 BugType *BT_call_arg;
28 BugType *BT_msg_undef;
29 BugType *BT_msg_arg;
Zhongxing Xu2055eff2009-11-24 07:06:39 +000030 BugType *BT_struct_ret;
31 BugType *BT_void_ptr;
Ted Kremenekf493f492009-11-11 05:50:44 +000032public:
Zhongxing Xud02174c2009-11-24 04:45:44 +000033 CallAndMessageChecker() :
Ted Kremenekc79d7d42009-11-21 01:25:37 +000034 BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
Zhongxing Xu2055eff2009-11-24 07:06:39 +000035 BT_msg_undef(0), BT_msg_arg(0), BT_struct_ret(0), BT_void_ptr(0) {}
36
Ted Kremenekf493f492009-11-11 05:50:44 +000037 static void *getTag() {
38 static int x = 0;
39 return &x;
40 }
41 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Ted Kremenek64fa8582009-11-21 00:49:41 +000042 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
Ted Kremenekc79d7d42009-11-21 01:25:37 +000043private:
44 void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
Ted Kremenekf493f492009-11-11 05:50:44 +000045};
46} // end anonymous namespace
47
Zhongxing Xud02174c2009-11-24 04:45:44 +000048void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) {
49 Eng.registerCheck(new CallAndMessageChecker());
Zhongxing Xu8958fff2009-11-03 06:46:03 +000050}
51
Zhongxing Xud02174c2009-11-24 04:45:44 +000052void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
53 const CallExpr *CE) {
Ted Kremenek19d67b52009-11-23 22:22:01 +000054 ExplodedNode *N = C.GenerateSink();
Ted Kremenekc79d7d42009-11-21 01:25:37 +000055 if (!N)
56 return;
57
58 EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
59 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
60 bugreporter::GetCalleeExpr(N));
61 C.EmitReport(R);
62}
63
Zhongxing Xud02174c2009-11-24 04:45:44 +000064void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
65 const CallExpr *CE){
Ted Kremenekc79d7d42009-11-21 01:25:37 +000066
67 const Expr *Callee = CE->getCallee()->IgnoreParens();
68 SVal L = C.getState()->getSVal(Callee);
69
70 if (L.isUndef()) {
71 if (!BT_call_undef)
72 BT_call_undef =
73 new BuiltinBug("Called function pointer is an undefined pointer value");
74 EmitBadCall(BT_call_undef, C, CE);
75 return;
76 }
77
78 if (isa<loc::ConcreteInt>(L)) {
79 if (!BT_call_null)
80 BT_call_null =
81 new BuiltinBug("Called function pointer is null (null dereference)");
82 EmitBadCall(BT_call_null, C, CE);
83 }
84
Zhongxing Xu8958fff2009-11-03 06:46:03 +000085 for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
86 I != E; ++I) {
87 if (C.getState()->getSVal(*I).isUndef()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +000088 if (ExplodedNode *N = C.GenerateSink()) {
Ted Kremenekc79d7d42009-11-21 01:25:37 +000089 if (!BT_call_arg)
90 BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
91 " is undefined");
Zhongxing Xu8958fff2009-11-03 06:46:03 +000092 // Generate a report for this bug.
Ted Kremenekc79d7d42009-11-21 01:25:37 +000093 EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
94 BT_call_arg->getName(), N);
Zhongxing Xu8958fff2009-11-03 06:46:03 +000095 R->addRange((*I)->getSourceRange());
96 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
97 C.EmitReport(R);
Ted Kremenek64fa8582009-11-21 00:49:41 +000098 return;
99 }
100 }
101 }
102}
103
Zhongxing Xud02174c2009-11-24 04:45:44 +0000104void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
105 const ObjCMessageExpr *ME) {
Ted Kremenek64fa8582009-11-21 00:49:41 +0000106
Ted Kremenek64fa8582009-11-21 00:49:41 +0000107 const GRState *state = C.getState();
Ted Kremenekc79d7d42009-11-21 01:25:37 +0000108
109 if (const Expr *receiver = ME->getReceiver())
110 if (state->getSVal(receiver).isUndef()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000111 if (ExplodedNode *N = C.GenerateSink()) {
Ted Kremenekc79d7d42009-11-21 01:25:37 +0000112 if (!BT_msg_undef)
113 BT_msg_undef =
114 new BuiltinBug("Receiver in message expression is a garbage value");
115 EnhancedBugReport *R =
116 new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
117 R->addRange(receiver->getSourceRange());
118 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
119 receiver);
120 C.EmitReport(R);
121 }
122 return;
123 }
124
125 // Check for any arguments that are uninitialized/undefined.
Zhongxing Xu2055eff2009-11-24 07:06:39 +0000126 for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
127 E = ME->arg_end(); I != E; ++I) {
Ted Kremenek64fa8582009-11-21 00:49:41 +0000128 if (state->getSVal(*I).isUndef()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000129 if (ExplodedNode *N = C.GenerateSink()) {
Ted Kremenekc79d7d42009-11-21 01:25:37 +0000130 if (!BT_msg_arg)
131 BT_msg_arg =
132 new BuiltinBug("Pass-by-value argument in message expression"
133 " is undefined");
Ted Kremenek64fa8582009-11-21 00:49:41 +0000134 // Generate a report for this bug.
Ted Kremenekc79d7d42009-11-21 01:25:37 +0000135 EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
136 BT_msg_arg->getName(), N);
Ted Kremenek64fa8582009-11-21 00:49:41 +0000137 R->addRange((*I)->getSourceRange());
138 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
139 C.EmitReport(R);
140 return;
Zhongxing Xu8958fff2009-11-03 06:46:03 +0000141 }
142 }
143 }
Zhongxing Xu2055eff2009-11-24 07:06:39 +0000144
145 // Check if the receiver was nil and then return value a struct.
146 if (const Expr *Receiver = ME->getReceiver()) {
147 SVal L_untested = state->getSVal(Receiver);
148 // Assume that the receiver is not NULL.
149 DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
150 const GRState *StNotNull = state->Assume(L, true);
151
152 // Assume that the receiver is NULL.
153 const GRState *StNull = state->Assume(L, false);
154
155 if (StNull) {
156 QualType RetTy = ME->getType();
157 if (RetTy->isRecordType()) {
158 if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
159 // The [0 ...] expressions will return garbage. Flag either an
160 // explicit or implicit error. Because of the structure of this
161 // function we currently do not bifurfacte the state graph at
162 // this point.
163 // FIXME: We should bifurcate and fill the returned struct with
164 // garbage.
165 if (ExplodedNode* N = C.GenerateSink(StNull)) {
166 if (!StNotNull) {
167 if (!BT_struct_ret) {
168 std::string sbuf;
169 llvm::raw_string_ostream os(sbuf);
170 os << "The receiver in the message expression is 'nil' and "
171 "results in the returned value (of type '"
172 << ME->getType().getAsString()
173 << "') to be garbage or otherwise undefined";
174 BT_struct_ret = new BuiltinBug(os.str().c_str());
175 }
176
177 EnhancedBugReport *R = new EnhancedBugReport(*BT_struct_ret,
178 BT_struct_ret->getName(), N);
179 R->addRange(Receiver->getSourceRange());
180 R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
181 Receiver);
182 C.EmitReport(R);
183 return;
184 }
185 else
186 // Do not report implicit bug.
187 return;
188 }
189 }
190 } else {
191 ASTContext &Ctx = C.getASTContext();
192 if (RetTy != Ctx.VoidTy) {
193 if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
194 // sizeof(void *)
195 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
196 // sizeof(return type)
197 const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
198
199 if (voidPtrSize < returnTypeSize) {
200 if (ExplodedNode* N = C.GenerateSink(StNull)) {
201 if (!StNotNull) {
202 if (!BT_struct_ret) {
203 std::string sbuf;
204 llvm::raw_string_ostream os(sbuf);
205 os << "The receiver in the message expression is 'nil' and "
206 "results in the returned value (of type '"
207 << ME->getType().getAsString()
208 << "' and of size "
209 << returnTypeSize / 8
210 << " bytes) to be garbage or otherwise undefined";
211 BT_void_ptr = new BuiltinBug(os.str().c_str());
212 }
213
214 EnhancedBugReport *R = new EnhancedBugReport(*BT_void_ptr,
215 BT_void_ptr->getName(), N);
216 R->addRange(Receiver->getSourceRange());
217 R->addVisitorCreator(
218 bugreporter::registerTrackNullOrUndefValue, Receiver);
219 C.EmitReport(R);
220 return;
221 } else
222 // Do not report implicit bug.
223 return;
224 }
225 }
226 else if (!StNotNull) {
227 // Handle the safe cases where the return value is 0 if the
228 // receiver is nil.
229 //
230 // FIXME: For now take the conservative approach that we only
231 // return null values if we *know* that the receiver is nil.
232 // This is because we can have surprises like:
233 //
234 // ... = [[NSScreens screens] objectAtIndex:0];
235 //
236 // What can happen is that [... screens] could return nil, but
237 // it most likely isn't nil. We should assume the semantics
238 // of this case unless we have *a lot* more knowledge.
239 //
240 SVal V = C.getValueManager().makeZeroVal(ME->getType());
241 C.GenerateNode(StNull->BindExpr(ME, V));
242 return;
243 }
244 }
245 }
246 }
247 }
248 // Do not propagate null state.
249 if (StNotNull)
250 C.GenerateNode(StNotNull);
251 }
Zhongxing Xu8958fff2009-11-03 06:46:03 +0000252}