blob: 5c428f5370918df1cd2128b7e118699d37ac5c58 [file] [log] [blame]
Ted Kremenek78d46242008-07-22 16:21:24 +00001//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- 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 file defines the BugType classes used by GRExprEngine to report
11// bugs derived from builtin checks in the path-sensitive engine.
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek1053d242009-11-06 02:24:13 +000015#include "GRExprEngineInternalChecks.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000016#include "clang/Analysis/PathSensitive/BugReporter.h"
17#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenekc26a8b02009-07-22 21:46:56 +000018#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
Ted Kremenekb107c4b2009-11-04 04:24:16 +000019#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
Ted Kremenekdd986cc2009-05-07 00:45:33 +000020#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek8aed8062008-10-31 00:13:20 +000021#include "clang/Basic/SourceManager.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000022#include "llvm/Support/Compiler.h"
Ted Kremenekad51a602008-10-31 00:18:30 +000023#include "llvm/Support/raw_ostream.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000024
25using namespace clang;
Ted Kremenek53500662009-07-22 17:55:28 +000026using namespace clang::bugreporter;
Ted Kremenek78d46242008-07-22 16:21:24 +000027
28//===----------------------------------------------------------------------===//
29// Utility functions.
30//===----------------------------------------------------------------------===//
31
32template <typename ITERATOR> inline
Zhongxing Xuc5619d92009-08-06 01:32:16 +000033ExplodedNode* GetNode(ITERATOR I) {
Ted Kremenek78d46242008-07-22 16:21:24 +000034 return *I;
35}
36
Ted Kremenek78d46242008-07-22 16:21:24 +000037//===----------------------------------------------------------------------===//
38// Bug Descriptions.
39//===----------------------------------------------------------------------===//
Zhongxing Xuec9227f2009-10-29 02:09:30 +000040namespace clang {
41class BuiltinBugReport : public RangedBugReport {
Ted Kremenekdd986cc2009-05-07 00:45:33 +000042public:
43 BuiltinBugReport(BugType& bt, const char* desc,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000044 ExplodedNode *n)
Ted Kremenek0c313172009-05-13 19:16:35 +000045 : RangedBugReport(bt, desc, n) {}
Mike Stump1eb44332009-09-09 15:08:12 +000046
Ted Kremenek85ac9342009-05-15 05:25:09 +000047 BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000048 ExplodedNode *n)
Mike Stump1eb44332009-09-09 15:08:12 +000049 : RangedBugReport(bt, shortDesc, desc, n) {}
50
Ted Kremenekdd986cc2009-05-07 00:45:33 +000051 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000052 const ExplodedNode* N);
Mike Stump1eb44332009-09-09 15:08:12 +000053};
54
Zhongxing Xuec9227f2009-10-29 02:09:30 +000055void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
56 const ExplodedNode* N) {
57 static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
58}
Mike Stump1eb44332009-09-09 15:08:12 +000059
Ted Kremenekdd986cc2009-05-07 00:45:33 +000060template <typename ITER>
61void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
62 for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
63 GetNode(I)));
Mike Stump1eb44332009-09-09 15:08:12 +000064}
Mike Stump1eb44332009-09-09 15:08:12 +000065
Ted Kremenek0c313172009-05-13 19:16:35 +000066class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
Ted Kremenek21fe8372009-02-19 04:06:22 +000067public:
68 NilReceiverStructRet(GRExprEngine* eng) :
Ted Kremenek0c313172009-05-13 19:16:35 +000069 BuiltinBug(eng, "'nil' receiver with struct return type") {}
Ted Kremenek21fe8372009-02-19 04:06:22 +000070
Ted Kremenek0c313172009-05-13 19:16:35 +000071 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek21fe8372009-02-19 04:06:22 +000072 for (GRExprEngine::nil_receiver_struct_ret_iterator
73 I=Eng.nil_receiver_struct_ret_begin(),
74 E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
75
76 std::string sbuf;
77 llvm::raw_string_ostream os(sbuf);
78 PostStmt P = cast<PostStmt>((*I)->getLocation());
Ted Kremenek5f85e172009-07-22 22:35:28 +000079 const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
Ted Kremenek21fe8372009-02-19 04:06:22 +000080 os << "The receiver in the message expression is 'nil' and results in the"
81 " returned value (of type '"
82 << ME->getType().getAsString()
Ted Kremenek5b9bd212009-09-11 22:07:28 +000083 << "') to be garbage or otherwise undefined";
Ted Kremenek21fe8372009-02-19 04:06:22 +000084
Ted Kremenek0c313172009-05-13 19:16:35 +000085 BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
Ted Kremenek21fe8372009-02-19 04:06:22 +000086 R->addRange(ME->getReceiver()->getSourceRange());
87 BR.EmitReport(R);
88 }
89 }
Mike Stump1eb44332009-09-09 15:08:12 +000090
Ted Kremenek0c313172009-05-13 19:16:35 +000091 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000092 const ExplodedNode* N,
Ted Kremenek0c313172009-05-13 19:16:35 +000093 BuiltinBugReport *R) {
Ted Kremenek85ac9342009-05-15 05:25:09 +000094 registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
Ted Kremenek0c313172009-05-13 19:16:35 +000095 }
Ted Kremenek21fe8372009-02-19 04:06:22 +000096};
Ted Kremenek899b3de2009-04-08 03:07:17 +000097
Ted Kremenek0c313172009-05-13 19:16:35 +000098class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
Ted Kremenek899b3de2009-04-08 03:07:17 +000099public:
100 NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
Ted Kremenek0c313172009-05-13 19:16:35 +0000101 BuiltinBug(eng,
102 "'nil' receiver with return type larger than sizeof(void *)") {}
Mike Stump1eb44332009-09-09 15:08:12 +0000103
Ted Kremenek0c313172009-05-13 19:16:35 +0000104 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek899b3de2009-04-08 03:07:17 +0000105 for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
106 I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
107 E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
Mike Stump1eb44332009-09-09 15:08:12 +0000108
Ted Kremenek899b3de2009-04-08 03:07:17 +0000109 std::string sbuf;
110 llvm::raw_string_ostream os(sbuf);
111 PostStmt P = cast<PostStmt>((*I)->getLocation());
Ted Kremenek5f85e172009-07-22 22:35:28 +0000112 const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
Ted Kremenek899b3de2009-04-08 03:07:17 +0000113 os << "The receiver in the message expression is 'nil' and results in the"
114 " returned value (of type '"
115 << ME->getType().getAsString()
116 << "' and of size "
117 << Eng.getContext().getTypeSize(ME->getType()) / 8
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000118 << " bytes) to be garbage or otherwise undefined";
Mike Stump1eb44332009-09-09 15:08:12 +0000119
Ted Kremenek0c313172009-05-13 19:16:35 +0000120 BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
Ted Kremenek899b3de2009-04-08 03:07:17 +0000121 R->addRange(ME->getReceiver()->getSourceRange());
122 BR.EmitReport(R);
123 }
Mike Stump1eb44332009-09-09 15:08:12 +0000124 }
Ted Kremenek0c313172009-05-13 19:16:35 +0000125 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000126 const ExplodedNode* N,
Ted Kremenek0c313172009-05-13 19:16:35 +0000127 BuiltinBugReport *R) {
Ted Kremenek85ac9342009-05-15 05:25:09 +0000128 registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
Ted Kremenek899b3de2009-04-08 03:07:17 +0000129 }
130};
Mike Stump1eb44332009-09-09 15:08:12 +0000131
Ted Kremenek78d46242008-07-22 16:21:24 +0000132class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
133public:
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000134 UndefResult(GRExprEngine* eng)
135 : BuiltinBug(eng,"Undefined or garbage result",
136 "Result of operation is garbage or undefined") {}
Mike Stump1eb44332009-09-09 15:08:12 +0000137
Ted Kremenekcf118d42009-02-04 23:49:09 +0000138 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000139 for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(),
140 E = Eng.undef_results_end(); I!=E; ++I) {
141
142 ExplodedNode *N = *I;
143 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
144 BuiltinBugReport *report = NULL;
145
146 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
147 llvm::SmallString<256> sbuf;
148 llvm::raw_svector_ostream OS(sbuf);
149 const GRState *ST = N->getState();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000150 const Expr *Ex = NULL;
151 bool isLeft = true;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000152
153 if (ST->getSVal(B->getLHS()).isUndef()) {
154 Ex = B->getLHS()->IgnoreParenCasts();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000155 isLeft = true;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000156 }
Ted Kremenek24c411b2009-09-15 17:43:54 +0000157 else if (ST->getSVal(B->getRHS()).isUndef()) {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000158 Ex = B->getRHS()->IgnoreParenCasts();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000159 isLeft = false;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000160 }
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000161
162 if (Ex) {
163 OS << "The " << (isLeft ? "left" : "right")
Ted Kremenek112ba7e2009-09-24 00:44:26 +0000164 << " operand of '"
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000165 << BinaryOperator::getOpcodeStr(B->getOpcode())
Ted Kremenek112ba7e2009-09-24 00:44:26 +0000166 << "' is a garbage value";
Ted Kremenek24c411b2009-09-15 17:43:54 +0000167 }
168 else {
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000169 // Neither operand was undefined, but the result is undefined.
Ted Kremenek24c411b2009-09-15 17:43:54 +0000170 OS << "The result of the '"
171 << BinaryOperator::getOpcodeStr(B->getOpcode())
172 << "' expression is undefined";
173 }
174
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000175 // FIXME: Use StringRefs to pass string information.
176 report = new BuiltinBugReport(*this, OS.str().str().c_str(), N);
Ted Kremenek24c411b2009-09-15 17:43:54 +0000177 if (Ex) report->addRange(Ex->getSourceRange());
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000178 }
179 else {
180 report = new BuiltinBugReport(*this,
181 "Expression evaluates to an uninitialized"
182 " or undefined value", N);
183 }
184
185 BR.EmitReport(report);
186 }
187 }
188
189 void registerInitialVisitors(BugReporterContext& BRC,
190 const ExplodedNode* N,
191 BuiltinBugReport *R) {
192
193 const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt();
194 const Stmt *X = S;
195
196 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
197 const GRState *ST = N->getState();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000198 if (ST->getSVal(B->getLHS()).isUndef())
199 X = B->getLHS();
200 else if (ST->getSVal(B->getRHS()).isUndef())
201 X = B->getRHS();
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000202 }
203
204 registerTrackNullOrUndefValue(BRC, X, N);
Ted Kremenek78d46242008-07-22 16:21:24 +0000205 }
206};
Mike Stump1eb44332009-09-09 15:08:12 +0000207
Ted Kremenek85ac9342009-05-15 05:25:09 +0000208class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
209 const Stmt *Arg;
210public:
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000211 ArgReport(BugType& bt, const char* desc, ExplodedNode *n,
Ted Kremenek85ac9342009-05-15 05:25:09 +0000212 const Stmt *arg)
213 : BuiltinBugReport(bt, desc, n), Arg(arg) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000214
Ted Kremenek85ac9342009-05-15 05:25:09 +0000215 ArgReport(BugType& bt, const char *shortDesc, const char *desc,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000216 ExplodedNode *n, const Stmt *arg)
Mike Stump1eb44332009-09-09 15:08:12 +0000217 : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {}
218
219 const Stmt *getArg() const { return Arg; }
Ted Kremenek78d46242008-07-22 16:21:24 +0000220};
221
Ted Kremenek78d46242008-07-22 16:21:24 +0000222class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
223 struct VISIBILITY_HIDDEN FindUndefExpr {
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000224 GRStateManager& VM;
225 const GRState* St;
Mike Stump1eb44332009-09-09 15:08:12 +0000226
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000227 FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000228
229 Expr* FindExpr(Expr* Ex) {
Ted Kremenek78d46242008-07-22 16:21:24 +0000230 if (!MatchesCriteria(Ex))
Ted Kremenekb7714b22008-07-30 17:49:12 +0000231 return 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000232
Ted Kremenekb7714b22008-07-30 17:49:12 +0000233 for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
Ted Kremenek78d46242008-07-22 16:21:24 +0000234 if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
235 Expr* E2 = FindExpr(ExI);
236 if (E2) return E2;
237 }
Mike Stump1eb44332009-09-09 15:08:12 +0000238
Ted Kremenek78d46242008-07-22 16:21:24 +0000239 return Ex;
240 }
Mike Stump1eb44332009-09-09 15:08:12 +0000241
Ted Kremenek23ec48c2009-06-18 23:58:37 +0000242 bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); }
Ted Kremenek78d46242008-07-22 16:21:24 +0000243 };
Mike Stump1eb44332009-09-09 15:08:12 +0000244
Ted Kremenek78d46242008-07-22 16:21:24 +0000245public:
Ted Kremenekcf118d42009-02-04 23:49:09 +0000246 UndefBranch(GRExprEngine *eng)
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000247 : BuiltinBug(eng,"Use of garbage value",
248 "Branch condition evaluates to an undefined or garbage value")
249 {}
Mike Stump1eb44332009-09-09 15:08:12 +0000250
Ted Kremenekcf118d42009-02-04 23:49:09 +0000251 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek78d46242008-07-22 16:21:24 +0000252 for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
253 E=Eng.undef_branches_end(); I!=E; ++I) {
254
255 // What's going on here: we want to highlight the subexpression of the
256 // condition that is the most likely source of the "uninitialized
257 // branch condition." We do a recursive walk of the condition's
258 // subexpressions and roughly look for the most nested subexpression
259 // that binds to Undefined. We then highlight that expression's range.
Ted Kremenek78d46242008-07-22 16:21:24 +0000260 BlockEdge B = cast<BlockEdge>((*I)->getLocation());
261 Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
262 assert (Ex && "Block must have a terminator.");
263
264 // Get the predecessor node and check if is a PostStmt with the Stmt
265 // being the terminator condition. We want to inspect the state
266 // of that node instead because it will contain main information about
267 // the subexpressions.
Ted Kremenek78d46242008-07-22 16:21:24 +0000268 assert (!(*I)->pred_empty());
269
270 // Note: any predecessor will do. They should have identical state,
271 // since all the BlockEdge did was act as an error sink since the value
272 // had to already be undefined.
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000273 ExplodedNode *N = *(*I)->pred_begin();
Ted Kremenek78d46242008-07-22 16:21:24 +0000274 ProgramPoint P = N->getLocation();
Ted Kremenek4adc81e2008-08-13 04:27:00 +0000275 const GRState* St = (*I)->getState();
Ted Kremenek78d46242008-07-22 16:21:24 +0000276
277 if (PostStmt* PS = dyn_cast<PostStmt>(&P))
278 if (PS->getStmt() == Ex)
279 St = N->getState();
280
281 FindUndefExpr FindIt(Eng.getStateManager(), St);
282 Ex = FindIt.FindExpr(Ex);
283
Ted Kremenek85ac9342009-05-15 05:25:09 +0000284 ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex);
Ted Kremenekcf118d42009-02-04 23:49:09 +0000285 R->addRange(Ex->getSourceRange());
286 BR.EmitReport(R);
Ted Kremenek78d46242008-07-22 16:21:24 +0000287 }
288 }
Mike Stump1eb44332009-09-09 15:08:12 +0000289
Ted Kremenek85ac9342009-05-15 05:25:09 +0000290 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000291 const ExplodedNode* N,
Ted Kremenek85ac9342009-05-15 05:25:09 +0000292 BuiltinBugReport *R) {
293 registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
294 N);
295 }
Ted Kremenek78d46242008-07-22 16:21:24 +0000296};
297
Zhongxing Xuec9227f2009-10-29 02:09:30 +0000298} // end clang namespace
Ted Kremenekbc3a0212009-10-30 17:24:47 +0000299
Ted Kremenek78d46242008-07-22 16:21:24 +0000300//===----------------------------------------------------------------------===//
301// Check registration.
Ted Kremenekcf118d42009-02-04 23:49:09 +0000302//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000303
304void GRExprEngine::RegisterInternalChecks() {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000305 // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
306 // are different than what probably many checks will do since they don't
307 // create BugReports on-the-fly but instead wait until GRExprEngine finishes
308 // analyzing a function. Generation of BugReport objects is done via a call
309 // to 'FlushReports' from BugReporter.
Ted Kremenekcf118d42009-02-04 23:49:09 +0000310 BR.Register(new UndefBranch(this));
Ted Kremenekcf118d42009-02-04 23:49:09 +0000311 BR.Register(new UndefResult(this));
Ted Kremenek21fe8372009-02-19 04:06:22 +0000312 BR.Register(new NilReceiverStructRet(this));
Ted Kremenek899b3de2009-04-08 03:07:17 +0000313 BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
Mike Stump1eb44332009-09-09 15:08:12 +0000314
Ted Kremenekcf118d42009-02-04 23:49:09 +0000315 // The following checks do not need to have their associated BugTypes
316 // explicitly registered with the BugReporter. If they issue any BugReports,
317 // their associated BugType will get registered with the BugReporter
318 // automatically. Note that the check itself is owned by the GRExprEngine
Ted Kremenek36df58a2009-11-06 20:47:51 +0000319 // object.
Ted Kremenekf493f492009-11-11 05:50:44 +0000320 RegisterAttrNonNullChecker(*this);
321 RegisterUndefinedArgChecker(*this);
Ted Kremenekb4b817d2009-11-11 03:26:34 +0000322 RegisterDereferenceChecker(*this);
Ted Kremenek84b35952009-11-06 21:51:50 +0000323 RegisterVLASizeChecker(*this);
324 RegisterDivZeroChecker(*this);
325 RegisterReturnStackAddressChecker(*this);
326 RegisterReturnUndefChecker(*this);
Zhongxing Xud6944852009-11-11 13:42:54 +0000327 RegisterUndefinedArraySubscriptChecker(*this);
Zhongxing Xuc3372e02009-11-22 12:29:52 +0000328 RegisterUndefinedAssignmentChecker(*this);
Ted Kremenek78d46242008-07-22 16:21:24 +0000329}