blob: 3945ed095df4ed846994ce62f36b4863b348395a [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
14#include "GRExprEngineExperimentalChecks.h"
15#include "clang/Checker/BugReporter/BugType.h"
16#include "clang/Checker/PathSensitive/CheckerVisitor.h"
17#include "clang/Checker/PathSensitive/GRState.h"
18#include "clang/Checker/PathSensitive/GRStateTrait.h"
19#include "clang/Checker/PathSensitive/SymbolManager.h"
20#include "llvm/ADT/ImmutableMap.h"
21
22using namespace clang;
23
24namespace {
25
Zhongxing Xu9843ba92010-07-19 01:52:29 +000026struct StreamState {
27 enum Kind { Opened, Closed, OpenFailed } K;
28 const Stmt *S;
29
30 StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
31
32 bool isOpened() const { return K == Opened; }
33 bool isClosed() const { return K == Closed; }
34 bool isOpenFailed() const { return K == OpenFailed; }
35
36 bool operator==(const StreamState &X) const {
37 return K == X.K && S == X.S;
38 }
39
40 static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
41 static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
42 static StreamState getOpenFailed(const Stmt *s) { return StreamState(OpenFailed, s); }
43
44 void Profile(llvm::FoldingSetNodeID &ID) const {
45 ID.AddInteger(K);
46 ID.AddPointer(S);
47 }
48};
49
Zhongxing Xuc1960952010-06-16 05:38:05 +000050class StreamChecker : public CheckerVisitor<StreamChecker> {
Zhongxing Xu9843ba92010-07-19 01:52:29 +000051 IdentifierInfo *II_fopen, *II_fclose,*II_fread, *II_fwrite,
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000052 *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
53 *II_clearerr, *II_feof, *II_ferror, *II_fileno;
Zhongxing Xu9843ba92010-07-19 01:52:29 +000054 BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose;
Zhongxing Xuc1960952010-06-16 05:38:05 +000055
56public:
Zhongxing Xu23d90f92010-06-18 02:47:46 +000057 StreamChecker()
Zhongxing Xu9843ba92010-07-19 01:52:29 +000058 : II_fopen(0), II_fclose(0), II_fread(0), II_fwrite(0),
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000059 II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
60 II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
Zhongxing Xu9843ba92010-07-19 01:52:29 +000061 BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0) {}
Zhongxing Xuc1960952010-06-16 05:38:05 +000062
63 static void *getTag() {
64 static int x;
65 return &x;
66 }
67
68 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
69
70private:
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000071 void Fopen(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu9843ba92010-07-19 01:52:29 +000072 void Fclose(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000073 void Fread(CheckerContext &C, const CallExpr *CE);
74 void Fwrite(CheckerContext &C, const CallExpr *CE);
75 void Fseek(CheckerContext &C, const CallExpr *CE);
76 void Ftell(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +000077 void Rewind(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc7de88b2010-06-22 07:50:21 +000078 void Fgetpos(CheckerContext &C, const CallExpr *CE);
79 void Fsetpos(CheckerContext &C, const CallExpr *CE);
80 void Clearerr(CheckerContext &C, const CallExpr *CE);
81 void Feof(CheckerContext &C, const CallExpr *CE);
82 void Ferror(CheckerContext &C, const CallExpr *CE);
83 void Fileno(CheckerContext &C, const CallExpr *CE);
84
85 // Return true indicates the stream pointer is NULL.
Zhongxing Xu12d213d2010-06-24 12:52:28 +000086 const GRState *CheckNullStream(SVal SV, const GRState *state,
87 CheckerContext &C);
Zhongxing Xu9843ba92010-07-19 01:52:29 +000088 const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
89 CheckerContext &C);
Zhongxing Xuc1960952010-06-16 05:38:05 +000090};
91
Zhongxing Xu23d90f92010-06-18 02:47:46 +000092} // end anonymous namespace
Zhongxing Xuc1960952010-06-16 05:38:05 +000093
Zhongxing Xu9843ba92010-07-19 01:52:29 +000094namespace clang {
95 template <>
96 struct GRStateTrait<StreamState>
97 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
98 static void *GDMIndex() { return StreamChecker::getTag(); }
99 };
100}
101
Zhongxing Xuc1960952010-06-16 05:38:05 +0000102void clang::RegisterStreamChecker(GRExprEngine &Eng) {
103 Eng.registerCheck(new StreamChecker());
104}
105
106bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
107 const GRState *state = C.getState();
108 const Expr *Callee = CE->getCallee();
109 SVal L = state->getSVal(Callee);
110 const FunctionDecl *FD = L.getAsFunctionDecl();
111 if (!FD)
112 return false;
113
114 ASTContext &Ctx = C.getASTContext();
115 if (!II_fopen)
116 II_fopen = &Ctx.Idents.get("fopen");
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000117 if (!II_fclose)
118 II_fclose = &Ctx.Idents.get("fclose");
Zhongxing Xuc1960952010-06-16 05:38:05 +0000119 if (!II_fread)
120 II_fread = &Ctx.Idents.get("fread");
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000121 if (!II_fwrite)
122 II_fwrite = &Ctx.Idents.get("fwrite");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000123 if (!II_fseek)
124 II_fseek = &Ctx.Idents.get("fseek");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000125 if (!II_ftell)
126 II_ftell = &Ctx.Idents.get("ftell");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000127 if (!II_rewind)
128 II_rewind = &Ctx.Idents.get("rewind");
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000129 if (!II_fgetpos)
130 II_fgetpos = &Ctx.Idents.get("fgetpos");
131 if (!II_fsetpos)
132 II_fsetpos = &Ctx.Idents.get("fsetpos");
133 if (!II_clearerr)
134 II_clearerr = &Ctx.Idents.get("clearerr");
135 if (!II_feof)
136 II_feof = &Ctx.Idents.get("feof");
137 if (!II_ferror)
138 II_ferror = &Ctx.Idents.get("ferror");
139 if (!II_fileno)
140 II_fileno = &Ctx.Idents.get("fileno");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000141
Zhongxing Xuc1960952010-06-16 05:38:05 +0000142 if (FD->getIdentifier() == II_fopen) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000143 Fopen(C, CE);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000144 return true;
145 }
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000146 if (FD->getIdentifier() == II_fclose) {
147 Fclose(C, CE);
148 return true;
149 }
Zhongxing Xuc1960952010-06-16 05:38:05 +0000150 if (FD->getIdentifier() == II_fread) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000151 Fread(C, CE);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000152 return true;
153 }
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000154 if (FD->getIdentifier() == II_fwrite) {
155 Fwrite(C, CE);
156 return true;
157 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000158 if (FD->getIdentifier() == II_fseek) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000159 Fseek(C, CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000160 return true;
161 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000162 if (FD->getIdentifier() == II_ftell) {
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000163 Ftell(C, CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000164 return true;
165 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000166 if (FD->getIdentifier() == II_rewind) {
167 Rewind(C, CE);
168 return true;
169 }
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000170 if (FD->getIdentifier() == II_fgetpos) {
171 Fgetpos(C, CE);
172 return true;
173 }
174 if (FD->getIdentifier() == II_fsetpos) {
175 Fsetpos(C, CE);
176 return true;
177 }
178 if (FD->getIdentifier() == II_clearerr) {
179 Clearerr(C, CE);
180 return true;
181 }
182 if (FD->getIdentifier() == II_feof) {
183 Feof(C, CE);
184 return true;
185 }
186 if (FD->getIdentifier() == II_ferror) {
187 Ferror(C, CE);
188 return true;
189 }
190 if (FD->getIdentifier() == II_fileno) {
191 Fileno(C, CE);
192 return true;
193 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000194
Zhongxing Xuc1960952010-06-16 05:38:05 +0000195 return false;
196}
197
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000198void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000199 const GRState *state = C.getState();
200 unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
201 ValueManager &ValMgr = C.getValueManager();
Zhongxing Xu70154852010-06-16 05:52:03 +0000202 DefinedSVal RetVal = cast<DefinedSVal>(ValMgr.getConjuredSymbolVal(0, CE,
203 Count));
Zhongxing Xuc1960952010-06-16 05:38:05 +0000204 state = state->BindExpr(CE, RetVal);
205
206 ConstraintManager &CM = C.getConstraintManager();
207 // Bifurcate the state into two: one with a valid FILE* pointer, the other
208 // with a NULL.
209 const GRState *stateNotNull, *stateNull;
Zhongxing Xu70154852010-06-16 05:52:03 +0000210 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, RetVal);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000211
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000212 SymbolRef Sym = RetVal.getAsSymbol();
213 assert(Sym);
214
215 // if RetVal is not NULL, set the symbol's state to Opened.
216 stateNotNull = stateNotNull->set<StreamState>(Sym, StreamState::getOpened(CE));
217 stateNull = stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
218
Zhongxing Xuc1960952010-06-16 05:38:05 +0000219 C.addTransition(stateNotNull);
220 C.addTransition(stateNull);
221}
222
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000223void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
224 const GRState *state = CheckDoubleClose(CE, C.getState(), C);
225 if (state)
226 C.addTransition(state);
227}
228
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000229void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xuc1960952010-06-16 05:38:05 +0000230 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000231 if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000232 return;
233}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000234
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000235void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
236 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000237 if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000238 return;
239}
240
241void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000242 const GRState *state = C.getState();
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000243 if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000244 return;
Zhongxing Xu0c2e8c82010-06-24 13:36:41 +0000245 // Check the legality of the 'whence' argument of 'fseek'.
246 SVal Whence = state->getSVal(CE->getArg(2));
247 bool WhenceIsLegal = true;
248 const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
249 if (!CI)
250 WhenceIsLegal = false;
251
252 int64_t x = CI->getValue().getSExtValue();
253 if (!(x == 0 || x == 1 || x == 2))
254 WhenceIsLegal = false;
255
256 if (!WhenceIsLegal) {
257 if (ExplodedNode *N = C.GenerateSink(state)) {
258 if (!BT_illegalwhence)
259 BT_illegalwhence = new BuiltinBug("Illegal whence argument",
260 "The whence argument to fseek() should be "
261 "SEEK_SET, SEEK_END, or SEEK_CUR.");
262 BugReport *R = new BugReport(*BT_illegalwhence,
263 BT_illegalwhence->getDescription(), N);
264 C.EmitReport(R);
265 }
266 return;
267 }
268
269 C.addTransition(state);
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000270}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000271
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000272void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000273 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000274 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000275 return;
276}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000277
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000278void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
279 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000280 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000281 return;
282}
283
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000284void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
285 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000286 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000287 return;
288}
289
290void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
291 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000292 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000293 return;
294}
295
296void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
297 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000298 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000299 return;
300}
301
302void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
303 const GRState *state = C.getState();
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000304 if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
Zhongxing Xuc7de88b2010-06-22 07:50:21 +0000305 return;
306}
307
308void StreamChecker::Ferror(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 Xuc7de88b2010-06-22 07:50:21 +0000311 return;
312}
313
314void StreamChecker::Fileno(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
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000320const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000321 CheckerContext &C) {
322 const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
323 if (!DV)
Ted Kremenek2b11fb22010-06-24 16:26:12 +0000324 return 0;
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000325
326 ConstraintManager &CM = C.getConstraintManager();
327 const GRState *stateNotNull, *stateNull;
328 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
329
330 if (!stateNotNull && stateNull) {
331 if (ExplodedNode *N = C.GenerateSink(stateNull)) {
332 if (!BT_nullfp)
333 BT_nullfp = new BuiltinBug("NULL stream pointer",
Zhongxing Xub3f40312010-06-16 05:56:39 +0000334 "Stream pointer might be NULL.");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000335 BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
336 C.EmitReport(R);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000337 }
Zhongxing Xu12d213d2010-06-24 12:52:28 +0000338 return 0;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000339 }
Zhongxing Xuab421302010-06-24 13:09:02 +0000340 return stateNotNull;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000341}
Zhongxing Xu9843ba92010-07-19 01:52:29 +0000342
343const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
344 const GRState *state,
345 CheckerContext &C) {
346 SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
347 assert(Sym);
348
349 const StreamState *SS = state->get<StreamState>(Sym);
350 assert(SS);
351
352 // Check: Double close a File Descriptor could cause undefined behaviour.
353 // Conforming to man-pages
354 if (SS->isClosed()) {
355 ExplodedNode *N = C.GenerateSink();
356 if (N) {
357 if (!BT_doubleclose)
358 BT_doubleclose = new BuiltinBug("Double fclose",
359 "Try to close a file Descriptor already"
360 " closed. Cause undefined behaviour.");
361 BugReport *R = new BugReport(*BT_doubleclose,
362 BT_doubleclose->getDescription(), N);
363 C.EmitReport(R);
364 }
365 return NULL;
366 }
367
368 // Close the File Descriptor.
369 return state->set<StreamState>(Sym, StreamState::getClosed(CE));
370}