blob: 2655be28a462052927bae15853b9371665e3bd80 [file] [log] [blame]
Zhongxing Xuc1960952010-06-16 05:38:05 +00001//===-- StreamChecker.cpp -----------------------------------------*- 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 checkers that model and check stream handling functions.
11//
12//===----------------------------------------------------------------------===//
13
Argyrios Kyrtzidisa0decc92011-02-15 21:25:03 +000014#include "ClangSACheckers.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000015#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
Zhongxing Xuc1960952010-06-16 05:38:05 +000021#include "llvm/ADT/ImmutableMap.h"
22
23using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000024using namespace ento;
Zhongxing Xuc1960952010-06-16 05:38:05 +000025
26namespace {
27
Zhongxing Xu9843ba92010-07-19 01:52:29 +000028struct StreamState {
Zhongxing Xu766c2012010-07-23 14:14:59 +000029 enum Kind { Opened, Closed, OpenFailed, Escaped } K;
Zhongxing Xu9843ba92010-07-19 01:52:29 +000030 const Stmt *S;
31
32 StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
33
34 bool isOpened() const { return K == Opened; }
35 bool isClosed() const { return K == Closed; }
Chris Lattnerfae96222010-09-03 04:34:38 +000036 //bool isOpenFailed() const { return K == OpenFailed; }
37 //bool isEscaped() const { return K == Escaped; }
Zhongxing Xu9843ba92010-07-19 01:52:29 +000038
39 bool operator==(const StreamState &X) const {
40 return K == X.K && S == X.S;
41 }
42
43 static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
44 static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
Zhongxing Xu47dc37f2010-07-22 14:01:01 +000045 static StreamState getOpenFailed(const Stmt *s) {
46 return StreamState(OpenFailed, s);
47 }
Zhongxing Xu766c2012010-07-23 14:14:59 +000048 static StreamState getEscaped(const Stmt *s) {
49 return StreamState(Escaped, s);
50 }
Zhongxing Xu9843ba92010-07-19 01:52:29 +000051
52 void Profile(llvm::FoldingSetNodeID &ID) const {
53 ID.AddInteger(K);
54 ID.AddPointer(S);
55 }
56};
57
Zhongxing Xuc1960952010-06-16 05:38:05 +000058class StreamChecker : public CheckerVisitor<StreamChecker> {
Zhongxing Xu47dc37f2010-07-22 14:01:01 +000059 IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite,
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000060 *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
61 *II_clearerr, *II_feof, *II_ferror, *II_fileno;
Zhongxing Xu766c2012010-07-23 14:14:59 +000062 BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
Zhongxing Xuc1960952010-06-16 05:38:05 +000063
64public:
Zhongxing Xu23d90f92010-06-18 02:47:46 +000065 StreamChecker()
Zhongxing Xu47dc37f2010-07-22 14:01:01 +000066 : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000067 II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
68 II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
Zhongxing Xu766c2012010-07-23 14:14:59 +000069 BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0),
70 BT_ResourceLeak(0) {}
Zhongxing Xuc1960952010-06-16 05:38:05 +000071
72 static void *getTag() {
73 static int x;
74 return &x;
75 }
76
Ted Kremenek9c149532010-12-01 21:57:22 +000077 virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
78 void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
Ted Kremeneke36de1f2011-01-11 02:34:45 +000079 void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
Zhongxing Xu766c2012010-07-23 14:14:59 +000080 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
Zhongxing Xuc1960952010-06-16 05:38:05 +000081
82private:
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000083 void Fopen(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu47dc37f2010-07-22 14:01:01 +000084 void Tmpfile(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu9843ba92010-07-19 01:52:29 +000085 void Fclose(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000086 void Fread(CheckerContext &C, const CallExpr *CE);
87 void Fwrite(CheckerContext &C, const CallExpr *CE);
88 void Fseek(CheckerContext &C, const CallExpr *CE);
89 void Ftell(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +000090 void Rewind(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000091 void Fgetpos(CheckerContext &C, const CallExpr *CE);
92 void Fsetpos(CheckerContext &C, const CallExpr *CE);
93 void Clearerr(CheckerContext &C, const CallExpr *CE);
94 void Feof(CheckerContext &C, const CallExpr *CE);
95 void Ferror(CheckerContext &C, const CallExpr *CE);
96 void Fileno(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu47dc37f2010-07-22 14:01:01 +000097
98 void OpenFileAux(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000099
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000100 const GRState *CheckNullStream(SVal SV, const GRState *state,
101 CheckerContext &C);
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000102 const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
103 CheckerContext &C);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000104};
105
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000106} // end anonymous namespace
Zhongxing Xuc1960952010-06-16 05:38:05 +0000107
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000108namespace clang {
Ted Kremenek9ef65372010-12-23 07:20:52 +0000109namespace ento {
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000110 template <>
111 struct GRStateTrait<StreamState>
112 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
113 static void *GDMIndex() { return StreamChecker::getTag(); }
114 };
115}
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +0000116}
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000117
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000118static void RegisterStreamChecker(ExprEngine &Eng) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000119 Eng.registerCheck(new StreamChecker());
120}
121
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000122void ento::registerStreamChecker(CheckerManager &mgr) {
123 mgr.addCheckerRegisterFunction(RegisterStreamChecker);
124}
125
Ted Kremenek9c149532010-12-01 21:57:22 +0000126bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000127 const GRState *state = C.getState();
128 const Expr *Callee = CE->getCallee();
129 SVal L = state->getSVal(Callee);
130 const FunctionDecl *FD = L.getAsFunctionDecl();
131 if (!FD)
132 return false;
133
134 ASTContext &Ctx = C.getASTContext();
135 if (!II_fopen)
136 II_fopen = &Ctx.Idents.get("fopen");
Zhongxing Xu47dc37f2010-07-22 14:01:01 +0000137 if (!II_tmpfile)
138 II_tmpfile = &Ctx.Idents.get("tmpfile");
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000139 if (!II_fclose)
140 II_fclose = &Ctx.Idents.get("fclose");
Zhongxing Xuc1960952010-06-16 05:38:05 +0000141 if (!II_fread)
142 II_fread = &Ctx.Idents.get("fread");
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000143 if (!II_fwrite)
144 II_fwrite = &Ctx.Idents.get("fwrite");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000145 if (!II_fseek)
146 II_fseek = &Ctx.Idents.get("fseek");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000147 if (!II_ftell)
148 II_ftell = &Ctx.Idents.get("ftell");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000149 if (!II_rewind)
150 II_rewind = &Ctx.Idents.get("rewind");
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000151 if (!II_fgetpos)
152 II_fgetpos = &Ctx.Idents.get("fgetpos");
153 if (!II_fsetpos)
154 II_fsetpos = &Ctx.Idents.get("fsetpos");
155 if (!II_clearerr)
156 II_clearerr = &Ctx.Idents.get("clearerr");
157 if (!II_feof)
158 II_feof = &Ctx.Idents.get("feof");
159 if (!II_ferror)
160 II_ferror = &Ctx.Idents.get("ferror");
161 if (!II_fileno)
162 II_fileno = &Ctx.Idents.get("fileno");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000163
Zhongxing Xuc1960952010-06-16 05:38:05 +0000164 if (FD->getIdentifier() == II_fopen) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000165 Fopen(C, CE);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000166 return true;
167 }
Zhongxing Xu47dc37f2010-07-22 14:01:01 +0000168 if (FD->getIdentifier() == II_tmpfile) {
169 Tmpfile(C, CE);
170 return true;
171 }
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000172 if (FD->getIdentifier() == II_fclose) {
173 Fclose(C, CE);
174 return true;
175 }
Zhongxing Xuc1960952010-06-16 05:38:05 +0000176 if (FD->getIdentifier() == II_fread) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000177 Fread(C, CE);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000178 return true;
179 }
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000180 if (FD->getIdentifier() == II_fwrite) {
181 Fwrite(C, CE);
182 return true;
183 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000184 if (FD->getIdentifier() == II_fseek) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000185 Fseek(C, CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000186 return true;
187 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000188 if (FD->getIdentifier() == II_ftell) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000189 Ftell(C, CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000190 return true;
191 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000192 if (FD->getIdentifier() == II_rewind) {
193 Rewind(C, CE);
194 return true;
195 }
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000196 if (FD->getIdentifier() == II_fgetpos) {
197 Fgetpos(C, CE);
198 return true;
199 }
200 if (FD->getIdentifier() == II_fsetpos) {
201 Fsetpos(C, CE);
202 return true;
203 }
204 if (FD->getIdentifier() == II_clearerr) {
205 Clearerr(C, CE);
206 return true;
207 }
208 if (FD->getIdentifier() == II_feof) {
209 Feof(C, CE);
210 return true;
211 }
212 if (FD->getIdentifier() == II_ferror) {
213 Ferror(C, CE);
214 return true;
215 }
216 if (FD->getIdentifier() == II_fileno) {
217 Fileno(C, CE);
218 return true;
219 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000220
Zhongxing Xuc1960952010-06-16 05:38:05 +0000221 return false;
222}
223
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000224void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xu47dc37f2010-07-22 14:01:01 +0000225 OpenFileAux(C, CE);
226}
227
228void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) {
229 OpenFileAux(C, CE);
230}
231
232void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000233 const GRState *state = C.getState();
234 unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000235 SValBuilder &svalBuilder = C.getSValBuilder();
236 DefinedSVal RetVal =
237 cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
Zhongxing Xuc1960952010-06-16 05:38:05 +0000238 state = state->BindExpr(CE, RetVal);
Zhongxing Xu47dc37f2010-07-22 14:01:01 +0000239
Zhongxing Xuc1960952010-06-16 05:38:05 +0000240 ConstraintManager &CM = C.getConstraintManager();
241 // Bifurcate the state into two: one with a valid FILE* pointer, the other
242 // with a NULL.
243 const GRState *stateNotNull, *stateNull;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000244 llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
Zhongxing Xu47dc37f2010-07-22 14:01:01 +0000245
Ted Kremenek80460372010-09-03 01:07:04 +0000246 if (SymbolRef Sym = RetVal.getAsSymbol()) {
247 // if RetVal is not NULL, set the symbol's state to Opened.
248 stateNotNull =
249 stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
250 stateNull =
251 stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000252
Ted Kremenek80460372010-09-03 01:07:04 +0000253 C.addTransition(stateNotNull);
254 C.addTransition(stateNull);
255 }
Zhongxing Xuc1960952010-06-16 05:38:05 +0000256}
257
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000258void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
259 const GRState *state = CheckDoubleClose(CE, C.getState(), C);
260 if (state)
261 C.addTransition(state);
262}
263
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000264void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000265 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000266 if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000267 return;
268}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000269
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000270void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
271 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000272 if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000273 return;
274}
275
276void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000277 const GRState *state = C.getState();
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000278 if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000279 return;
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000280 // Check the legality of the 'whence' argument of 'fseek'.
281 SVal Whence = state->getSVal(CE->getArg(2));
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000282 const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
Ted Kremenek02b49bb2010-09-07 20:45:26 +0000283
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000284 if (!CI)
Ted Kremenek02b49bb2010-09-07 20:45:26 +0000285 return;
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000286
287 int64_t x = CI->getValue().getSExtValue();
Ted Kremenek02b49bb2010-09-07 20:45:26 +0000288 if (x >= 0 && x <= 2)
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000289 return;
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000290
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000291 if (ExplodedNode *N = C.generateNode(state)) {
Ted Kremenek02b49bb2010-09-07 20:45:26 +0000292 if (!BT_illegalwhence)
293 BT_illegalwhence = new BuiltinBug("Illegal whence argument",
294 "The whence argument to fseek() should be "
295 "SEEK_SET, SEEK_END, or SEEK_CUR.");
296 BugReport *R = new BugReport(*BT_illegalwhence,
297 BT_illegalwhence->getDescription(), N);
298 C.EmitReport(R);
299 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000300}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000301
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000302void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000303 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000304 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000305 return;
306}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000307
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000308void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
309 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000310 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000311 return;
312}
313
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000314void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
315 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000316 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000317 return;
318}
319
320void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
321 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000322 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000323 return;
324}
325
326void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
327 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000328 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000329 return;
330}
331
332void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
333 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000334 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000335 return;
336}
337
338void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) {
339 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000340 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000341 return;
342}
343
344void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) {
345 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000346 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000347 return;
348}
349
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000350const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000351 CheckerContext &C) {
352 const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
353 if (!DV)
Ted Kremenek2b11fb22010-06-24 16:26:12 +0000354 return 0;
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000355
356 ConstraintManager &CM = C.getConstraintManager();
357 const GRState *stateNotNull, *stateNull;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000358 llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000359
360 if (!stateNotNull && stateNull) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000361 if (ExplodedNode *N = C.generateSink(stateNull)) {
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000362 if (!BT_nullfp)
363 BT_nullfp = new BuiltinBug("NULL stream pointer",
Zhongxing Xub3f40312010-06-16 05:56:39 +0000364 "Stream pointer might be NULL.");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000365 BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
366 C.EmitReport(R);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000367 }
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000368 return 0;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000369 }
Zhongxing Xuab421302010-06-24 13:09:02 +0000370 return stateNotNull;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000371}
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000372
373const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
Eli Friedmana7e68452010-08-22 01:00:03 +0000374 const GRState *state,
375 CheckerContext &C) {
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000376 SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
Ted Kremenek80460372010-09-03 01:07:04 +0000377 if (!Sym)
378 return state;
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000379
380 const StreamState *SS = state->get<StreamState>(Sym);
Zhongxing Xu1c7370f2010-08-05 23:24:13 +0000381
382 // If the file stream is not tracked, return.
383 if (!SS)
384 return state;
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000385
386 // Check: Double close a File Descriptor could cause undefined behaviour.
387 // Conforming to man-pages
388 if (SS->isClosed()) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000389 ExplodedNode *N = C.generateSink();
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000390 if (N) {
391 if (!BT_doubleclose)
Eli Friedmana7e68452010-08-22 01:00:03 +0000392 BT_doubleclose = new BuiltinBug("Double fclose",
393 "Try to close a file Descriptor already"
394 " closed. Cause undefined behaviour.");
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000395 BugReport *R = new BugReport(*BT_doubleclose,
Eli Friedmana7e68452010-08-22 01:00:03 +0000396 BT_doubleclose->getDescription(), N);
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000397 C.EmitReport(R);
398 }
399 return NULL;
400 }
401
402 // Close the File Descriptor.
403 return state->set<StreamState>(Sym, StreamState::getClosed(CE));
404}
Zhongxing Xu766c2012010-07-23 14:14:59 +0000405
Ted Kremenek9c149532010-12-01 21:57:22 +0000406void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
Zhongxing Xu766c2012010-07-23 14:14:59 +0000407 for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
Eli Friedmana7e68452010-08-22 01:00:03 +0000408 E = SymReaper.dead_end(); I != E; ++I) {
Zhongxing Xu766c2012010-07-23 14:14:59 +0000409 SymbolRef Sym = *I;
410 const GRState *state = C.getState();
411 const StreamState *SS = state->get<StreamState>(Sym);
412 if (!SS)
413 return;
414
415 if (SS->isOpened()) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000416 ExplodedNode *N = C.generateSink();
Zhongxing Xu766c2012010-07-23 14:14:59 +0000417 if (N) {
Eli Friedmana7e68452010-08-22 01:00:03 +0000418 if (!BT_ResourceLeak)
419 BT_ResourceLeak = new BuiltinBug("Resource Leak",
420 "Opened File never closed. Potential Resource leak.");
421 BugReport *R = new BugReport(*BT_ResourceLeak,
422 BT_ResourceLeak->getDescription(), N);
423 C.EmitReport(R);
Zhongxing Xu766c2012010-07-23 14:14:59 +0000424 }
425 }
426 }
427}
428
Ted Kremeneke36de1f2011-01-11 02:34:45 +0000429void StreamChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +0000430 ExprEngine &Eng) {
Zhongxing Xu766c2012010-07-23 14:14:59 +0000431 const GRState *state = B.getState();
432 typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
433 SymMap M = state->get<StreamState>();
434
435 for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
436 StreamState SS = I->second;
437 if (SS.isOpened()) {
438 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
439 if (N) {
440 if (!BT_ResourceLeak)
441 BT_ResourceLeak = new BuiltinBug("Resource Leak",
Eli Friedmana7e68452010-08-22 01:00:03 +0000442 "Opened File never closed. Potential Resource leak.");
Zhongxing Xu766c2012010-07-23 14:14:59 +0000443 BugReport *R = new BugReport(*BT_ResourceLeak,
Eli Friedmana7e68452010-08-22 01:00:03 +0000444 BT_ResourceLeak->getDescription(), N);
Zhongxing Xu766c2012010-07-23 14:14:59 +0000445 Eng.getBugReporter().EmitReport(R);
446 }
447 }
448 }
449}
450
451void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
452 const Expr *RetE = S->getRetValue();
453 if (!RetE)
454 return;
455
456 const GRState *state = C.getState();
457 SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
458
459 if (!Sym)
460 return;
461
462 const StreamState *SS = state->get<StreamState>(Sym);
463 if(!SS)
464 return;
465
466 if (SS->isOpened())
467 state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
468
469 C.addTransition(state);
470}