blob: 44919f13391595e34cbfaa4c35fb03f6809679fd [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
26class StreamChecker : public CheckerVisitor<StreamChecker> {
Zhongxing Xu23d90f92010-06-18 02:47:46 +000027 IdentifierInfo *II_fopen, *II_fread, *II_fseek, *II_ftell, *II_rewind;
Zhongxing Xuc1960952010-06-16 05:38:05 +000028 BuiltinBug *BT_nullfp;
29
30public:
Zhongxing Xu23d90f92010-06-18 02:47:46 +000031 StreamChecker()
32 : II_fopen(0), II_fread(0), II_fseek(0), II_ftell(0), II_rewind(0),
33 BT_nullfp(0) {}
Zhongxing Xuc1960952010-06-16 05:38:05 +000034
35 static void *getTag() {
36 static int x;
37 return &x;
38 }
39
40 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
41
42private:
43 void FOpen(CheckerContext &C, const CallExpr *CE);
44 void FRead(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu23d90f92010-06-18 02:47:46 +000045 void FSeek(CheckerContext &C, const CallExpr *CE);
46 void FTell(CheckerContext &C, const CallExpr *CE);
47 void Rewind(CheckerContext &C, const CallExpr *CE);
48 bool CheckNullStream(SVal SV, const GRState *state, CheckerContext &C);
Zhongxing Xuc1960952010-06-16 05:38:05 +000049};
50
Zhongxing Xu23d90f92010-06-18 02:47:46 +000051} // end anonymous namespace
Zhongxing Xuc1960952010-06-16 05:38:05 +000052
53void clang::RegisterStreamChecker(GRExprEngine &Eng) {
54 Eng.registerCheck(new StreamChecker());
55}
56
57bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
58 const GRState *state = C.getState();
59 const Expr *Callee = CE->getCallee();
60 SVal L = state->getSVal(Callee);
61 const FunctionDecl *FD = L.getAsFunctionDecl();
62 if (!FD)
63 return false;
64
65 ASTContext &Ctx = C.getASTContext();
66 if (!II_fopen)
67 II_fopen = &Ctx.Idents.get("fopen");
68
69 if (!II_fread)
70 II_fread = &Ctx.Idents.get("fread");
71
Zhongxing Xu23d90f92010-06-18 02:47:46 +000072 if (!II_fseek)
73 II_fseek = &Ctx.Idents.get("fseek");
74
75 if (!II_ftell)
76 II_ftell = &Ctx.Idents.get("ftell");
77
78 if (!II_rewind)
79 II_rewind = &Ctx.Idents.get("rewind");
80
Zhongxing Xuc1960952010-06-16 05:38:05 +000081 if (FD->getIdentifier() == II_fopen) {
82 FOpen(C, CE);
83 return true;
84 }
85
86 if (FD->getIdentifier() == II_fread) {
87 FRead(C, CE);
88 return true;
89 }
90
Zhongxing Xu23d90f92010-06-18 02:47:46 +000091 if (FD->getIdentifier() == II_fseek) {
92 FSeek(C, CE);
93 return true;
94 }
95
96 if (FD->getIdentifier() == II_ftell) {
97 FTell(C, CE);
98 return true;
99 }
100
101 if (FD->getIdentifier() == II_rewind) {
102 Rewind(C, CE);
103 return true;
104 }
105
Zhongxing Xuc1960952010-06-16 05:38:05 +0000106 return false;
107}
108
109void StreamChecker::FOpen(CheckerContext &C, const CallExpr *CE) {
110 const GRState *state = C.getState();
111 unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
112 ValueManager &ValMgr = C.getValueManager();
Zhongxing Xu70154852010-06-16 05:52:03 +0000113 DefinedSVal RetVal = cast<DefinedSVal>(ValMgr.getConjuredSymbolVal(0, CE,
114 Count));
Zhongxing Xuc1960952010-06-16 05:38:05 +0000115 state = state->BindExpr(CE, RetVal);
116
117 ConstraintManager &CM = C.getConstraintManager();
118 // Bifurcate the state into two: one with a valid FILE* pointer, the other
119 // with a NULL.
120 const GRState *stateNotNull, *stateNull;
Zhongxing Xu70154852010-06-16 05:52:03 +0000121 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, RetVal);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000122
123 C.addTransition(stateNotNull);
124 C.addTransition(stateNull);
125}
126
127void StreamChecker::FRead(CheckerContext &C, const CallExpr *CE) {
128 const GRState *state = C.getState();
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000129 if (CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
130 return;
131}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000132
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000133void StreamChecker::FSeek(CheckerContext &C, const CallExpr *CE) {
134 const GRState *state = C.getState();
135 if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
136 return;
137}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000138
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000139void StreamChecker::FTell(CheckerContext &C, const CallExpr *CE) {
140 const GRState *state = C.getState();
141 if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
142 return;
143}
Zhongxing Xuc1960952010-06-16 05:38:05 +0000144
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000145void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
146 const GRState *state = C.getState();
147 if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
148 return;
149}
150
151bool StreamChecker::CheckNullStream(SVal SV, const GRState *state,
152 CheckerContext &C) {
153 const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
154 if (!DV)
155 return false;
156
157 ConstraintManager &CM = C.getConstraintManager();
158 const GRState *stateNotNull, *stateNull;
159 llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
160
161 if (!stateNotNull && stateNull) {
162 if (ExplodedNode *N = C.GenerateSink(stateNull)) {
163 if (!BT_nullfp)
164 BT_nullfp = new BuiltinBug("NULL stream pointer",
Zhongxing Xub3f40312010-06-16 05:56:39 +0000165 "Stream pointer might be NULL.");
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000166 BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
167 C.EmitReport(R);
Zhongxing Xuc1960952010-06-16 05:38:05 +0000168 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000169 return true;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000170 }
Zhongxing Xu23d90f92010-06-18 02:47:46 +0000171 return false;
Zhongxing Xuc1960952010-06-16 05:38:05 +0000172}