blob: 62c361ca5581887c52533fc722ba216252caa349 [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 Kremenekdd986cc2009-05-07 00:45:33 +000019#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek8aed8062008-10-31 00:13:20 +000020#include "clang/Basic/SourceManager.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000021#include "llvm/Support/Compiler.h"
Ted Kremenekad51a602008-10-31 00:18:30 +000022#include "llvm/Support/raw_ostream.h"
Ted Kremenek78d46242008-07-22 16:21:24 +000023
24using namespace clang;
Ted Kremenek53500662009-07-22 17:55:28 +000025using namespace clang::bugreporter;
Ted Kremenek78d46242008-07-22 16:21:24 +000026
27//===----------------------------------------------------------------------===//
28// Utility functions.
29//===----------------------------------------------------------------------===//
30
31template <typename ITERATOR> inline
Zhongxing Xuc5619d92009-08-06 01:32:16 +000032ExplodedNode* GetNode(ITERATOR I) {
Ted Kremenek78d46242008-07-22 16:21:24 +000033 return *I;
34}
35
Ted Kremenek78d46242008-07-22 16:21:24 +000036//===----------------------------------------------------------------------===//
37// Bug Descriptions.
38//===----------------------------------------------------------------------===//
Zhongxing Xuec9227f2009-10-29 02:09:30 +000039namespace clang {
40class BuiltinBugReport : public RangedBugReport {
Ted Kremenekdd986cc2009-05-07 00:45:33 +000041public:
42 BuiltinBugReport(BugType& bt, const char* desc,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000043 ExplodedNode *n)
Ted Kremenek0c313172009-05-13 19:16:35 +000044 : RangedBugReport(bt, desc, n) {}
Mike Stump1eb44332009-09-09 15:08:12 +000045
Ted Kremenek85ac9342009-05-15 05:25:09 +000046 BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000047 ExplodedNode *n)
Mike Stump1eb44332009-09-09 15:08:12 +000048 : RangedBugReport(bt, shortDesc, desc, n) {}
49
Ted Kremenekdd986cc2009-05-07 00:45:33 +000050 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000051 const ExplodedNode* N);
Mike Stump1eb44332009-09-09 15:08:12 +000052};
53
Zhongxing Xuec9227f2009-10-29 02:09:30 +000054void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
55 const ExplodedNode* N) {
56 static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
57}
Mike Stump1eb44332009-09-09 15:08:12 +000058
Ted Kremenekdd986cc2009-05-07 00:45:33 +000059template <typename ITER>
60void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
61 for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
62 GetNode(I)));
Mike Stump1eb44332009-09-09 15:08:12 +000063}
Mike Stump1eb44332009-09-09 15:08:12 +000064
Ted Kremenek0c313172009-05-13 19:16:35 +000065class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
Ted Kremenek21fe8372009-02-19 04:06:22 +000066public:
67 NilReceiverStructRet(GRExprEngine* eng) :
Ted Kremenek0c313172009-05-13 19:16:35 +000068 BuiltinBug(eng, "'nil' receiver with struct return type") {}
Ted Kremenek21fe8372009-02-19 04:06:22 +000069
Ted Kremenek0c313172009-05-13 19:16:35 +000070 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek21fe8372009-02-19 04:06:22 +000071 for (GRExprEngine::nil_receiver_struct_ret_iterator
72 I=Eng.nil_receiver_struct_ret_begin(),
73 E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
74
75 std::string sbuf;
76 llvm::raw_string_ostream os(sbuf);
77 PostStmt P = cast<PostStmt>((*I)->getLocation());
Ted Kremenek5f85e172009-07-22 22:35:28 +000078 const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
Ted Kremenek21fe8372009-02-19 04:06:22 +000079 os << "The receiver in the message expression is 'nil' and results in the"
80 " returned value (of type '"
81 << ME->getType().getAsString()
Ted Kremenek5b9bd212009-09-11 22:07:28 +000082 << "') to be garbage or otherwise undefined";
Ted Kremenek21fe8372009-02-19 04:06:22 +000083
Ted Kremenek0c313172009-05-13 19:16:35 +000084 BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
Ted Kremenek21fe8372009-02-19 04:06:22 +000085 R->addRange(ME->getReceiver()->getSourceRange());
86 BR.EmitReport(R);
87 }
88 }
Mike Stump1eb44332009-09-09 15:08:12 +000089
Ted Kremenek0c313172009-05-13 19:16:35 +000090 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +000091 const ExplodedNode* N,
Ted Kremenek0c313172009-05-13 19:16:35 +000092 BuiltinBugReport *R) {
Ted Kremenek85ac9342009-05-15 05:25:09 +000093 registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
Ted Kremenek0c313172009-05-13 19:16:35 +000094 }
Ted Kremenek21fe8372009-02-19 04:06:22 +000095};
Ted Kremenek899b3de2009-04-08 03:07:17 +000096
Ted Kremenek0c313172009-05-13 19:16:35 +000097class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
Ted Kremenek899b3de2009-04-08 03:07:17 +000098public:
99 NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
Ted Kremenek0c313172009-05-13 19:16:35 +0000100 BuiltinBug(eng,
101 "'nil' receiver with return type larger than sizeof(void *)") {}
Mike Stump1eb44332009-09-09 15:08:12 +0000102
Ted Kremenek0c313172009-05-13 19:16:35 +0000103 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek899b3de2009-04-08 03:07:17 +0000104 for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
105 I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
106 E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
Mike Stump1eb44332009-09-09 15:08:12 +0000107
Ted Kremenek899b3de2009-04-08 03:07:17 +0000108 std::string sbuf;
109 llvm::raw_string_ostream os(sbuf);
110 PostStmt P = cast<PostStmt>((*I)->getLocation());
Ted Kremenek5f85e172009-07-22 22:35:28 +0000111 const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
Ted Kremenek899b3de2009-04-08 03:07:17 +0000112 os << "The receiver in the message expression is 'nil' and results in the"
113 " returned value (of type '"
114 << ME->getType().getAsString()
115 << "' and of size "
116 << Eng.getContext().getTypeSize(ME->getType()) / 8
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000117 << " bytes) to be garbage or otherwise undefined";
Mike Stump1eb44332009-09-09 15:08:12 +0000118
Ted Kremenek0c313172009-05-13 19:16:35 +0000119 BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
Ted Kremenek899b3de2009-04-08 03:07:17 +0000120 R->addRange(ME->getReceiver()->getSourceRange());
121 BR.EmitReport(R);
122 }
Mike Stump1eb44332009-09-09 15:08:12 +0000123 }
Ted Kremenek0c313172009-05-13 19:16:35 +0000124 void registerInitialVisitors(BugReporterContext& BRC,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000125 const ExplodedNode* N,
Ted Kremenek0c313172009-05-13 19:16:35 +0000126 BuiltinBugReport *R) {
Ted Kremenek85ac9342009-05-15 05:25:09 +0000127 registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
Ted Kremenek899b3de2009-04-08 03:07:17 +0000128 }
129};
Mike Stump1eb44332009-09-09 15:08:12 +0000130
Ted Kremenek78d46242008-07-22 16:21:24 +0000131class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
132public:
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000133 UndefResult(GRExprEngine* eng)
134 : BuiltinBug(eng,"Undefined or garbage result",
135 "Result of operation is garbage or undefined") {}
Mike Stump1eb44332009-09-09 15:08:12 +0000136
Ted Kremenekcf118d42009-02-04 23:49:09 +0000137 void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000138 for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(),
139 E = Eng.undef_results_end(); I!=E; ++I) {
140
141 ExplodedNode *N = *I;
142 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
143 BuiltinBugReport *report = NULL;
144
145 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
146 llvm::SmallString<256> sbuf;
147 llvm::raw_svector_ostream OS(sbuf);
148 const GRState *ST = N->getState();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000149 const Expr *Ex = NULL;
150 bool isLeft = true;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000151
152 if (ST->getSVal(B->getLHS()).isUndef()) {
153 Ex = B->getLHS()->IgnoreParenCasts();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000154 isLeft = true;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000155 }
Ted Kremenek24c411b2009-09-15 17:43:54 +0000156 else if (ST->getSVal(B->getRHS()).isUndef()) {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000157 Ex = B->getRHS()->IgnoreParenCasts();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000158 isLeft = false;
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000159 }
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000160
161 if (Ex) {
162 OS << "The " << (isLeft ? "left" : "right")
Ted Kremenek112ba7e2009-09-24 00:44:26 +0000163 << " operand of '"
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000164 << BinaryOperator::getOpcodeStr(B->getOpcode())
Ted Kremenek112ba7e2009-09-24 00:44:26 +0000165 << "' is a garbage value";
Ted Kremenek24c411b2009-09-15 17:43:54 +0000166 }
167 else {
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000168 // Neither operand was undefined, but the result is undefined.
Ted Kremenek24c411b2009-09-15 17:43:54 +0000169 OS << "The result of the '"
170 << BinaryOperator::getOpcodeStr(B->getOpcode())
171 << "' expression is undefined";
172 }
173
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000174 // FIXME: Use StringRefs to pass string information.
175 report = new BuiltinBugReport(*this, OS.str().str().c_str(), N);
Ted Kremenek24c411b2009-09-15 17:43:54 +0000176 if (Ex) report->addRange(Ex->getSourceRange());
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000177 }
178 else {
179 report = new BuiltinBugReport(*this,
180 "Expression evaluates to an uninitialized"
181 " or undefined value", N);
182 }
183
184 BR.EmitReport(report);
185 }
186 }
187
188 void registerInitialVisitors(BugReporterContext& BRC,
189 const ExplodedNode* N,
190 BuiltinBugReport *R) {
191
192 const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt();
193 const Stmt *X = S;
194
195 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
196 const GRState *ST = N->getState();
Ted Kremenek7c039bf2009-09-16 06:04:26 +0000197 if (ST->getSVal(B->getLHS()).isUndef())
198 X = B->getLHS();
199 else if (ST->getSVal(B->getRHS()).isUndef())
200 X = B->getRHS();
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000201 }
202
203 registerTrackNullOrUndefValue(BRC, X, N);
Ted Kremenek78d46242008-07-22 16:21:24 +0000204 }
205};
Mike Stump1eb44332009-09-09 15:08:12 +0000206
Zhongxing Xuec9227f2009-10-29 02:09:30 +0000207} // end clang namespace
Ted Kremenekbc3a0212009-10-30 17:24:47 +0000208
Ted Kremenek78d46242008-07-22 16:21:24 +0000209//===----------------------------------------------------------------------===//
210// Check registration.
Ted Kremenekcf118d42009-02-04 23:49:09 +0000211//===----------------------------------------------------------------------===//
Ted Kremenek78d46242008-07-22 16:21:24 +0000212
213void GRExprEngine::RegisterInternalChecks() {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000214 // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
215 // are different than what probably many checks will do since they don't
216 // create BugReports on-the-fly but instead wait until GRExprEngine finishes
217 // analyzing a function. Generation of BugReport objects is done via a call
218 // to 'FlushReports' from BugReporter.
Ted Kremenekcf118d42009-02-04 23:49:09 +0000219 BR.Register(new UndefResult(this));
Ted Kremenek21fe8372009-02-19 04:06:22 +0000220 BR.Register(new NilReceiverStructRet(this));
Ted Kremenek899b3de2009-04-08 03:07:17 +0000221 BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
Mike Stump1eb44332009-09-09 15:08:12 +0000222
Ted Kremenekcf118d42009-02-04 23:49:09 +0000223 // The following checks do not need to have their associated BugTypes
224 // explicitly registered with the BugReporter. If they issue any BugReports,
225 // their associated BugType will get registered with the BugReporter
226 // automatically. Note that the check itself is owned by the GRExprEngine
Ted Kremenek36df58a2009-11-06 20:47:51 +0000227 // object.
Ted Kremenekf493f492009-11-11 05:50:44 +0000228 RegisterAttrNonNullChecker(*this);
229 RegisterUndefinedArgChecker(*this);
Ted Kremenekb4b817d2009-11-11 03:26:34 +0000230 RegisterDereferenceChecker(*this);
Ted Kremenek84b35952009-11-06 21:51:50 +0000231 RegisterVLASizeChecker(*this);
232 RegisterDivZeroChecker(*this);
233 RegisterReturnStackAddressChecker(*this);
234 RegisterReturnUndefChecker(*this);
Zhongxing Xud6944852009-11-11 13:42:54 +0000235 RegisterUndefinedArraySubscriptChecker(*this);
Zhongxing Xuc3372e02009-11-22 12:29:52 +0000236 RegisterUndefinedAssignmentChecker(*this);
Zhongxing Xu0835e4c2009-11-23 03:20:54 +0000237 RegisterUndefBranchChecker(*this);
Ted Kremenek78d46242008-07-22 16:21:24 +0000238}