diff options
| author | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-06-18 02:47:46 +0000 |
|---|---|---|
| committer | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-06-18 02:47:46 +0000 |
| commit | e96a9132b89a808c4231e549a2748a52c731ba42 (patch) | |
| tree | ab6e24fbd43e1b3daf66a54e8545dae7e67621ee | |
| parent | 67d25f91c569761ff55e6875448a49e5b9addefd (diff) | |
| download | bcm5719-llvm-e96a9132b89a808c4231e549a2748a52c731ba42.tar.gz bcm5719-llvm-e96a9132b89a808c4231e549a2748a52c731ba42.zip | |
Add null stream check for more APIs.
llvm-svn: 106274
| -rw-r--r-- | clang/lib/Checker/StreamChecker.cpp | 86 | ||||
| -rw-r--r-- | clang/test/Analysis/stream.c | 26 |
2 files changed, 94 insertions, 18 deletions
diff --git a/clang/lib/Checker/StreamChecker.cpp b/clang/lib/Checker/StreamChecker.cpp index 01b7d83042e..44919f13391 100644 --- a/clang/lib/Checker/StreamChecker.cpp +++ b/clang/lib/Checker/StreamChecker.cpp @@ -24,11 +24,13 @@ using namespace clang; namespace { class StreamChecker : public CheckerVisitor<StreamChecker> { - IdentifierInfo *II_fopen, *II_fread; + IdentifierInfo *II_fopen, *II_fread, *II_fseek, *II_ftell, *II_rewind; BuiltinBug *BT_nullfp; public: - StreamChecker() : II_fopen(0), II_fread(0), BT_nullfp(0) {} + StreamChecker() + : II_fopen(0), II_fread(0), II_fseek(0), II_ftell(0), II_rewind(0), + BT_nullfp(0) {} static void *getTag() { static int x; @@ -40,9 +42,13 @@ public: private: void FOpen(CheckerContext &C, const CallExpr *CE); void FRead(CheckerContext &C, const CallExpr *CE); + void FSeek(CheckerContext &C, const CallExpr *CE); + void FTell(CheckerContext &C, const CallExpr *CE); + void Rewind(CheckerContext &C, const CallExpr *CE); + bool CheckNullStream(SVal SV, const GRState *state, CheckerContext &C); }; -} +} // end anonymous namespace void clang::RegisterStreamChecker(GRExprEngine &Eng) { Eng.registerCheck(new StreamChecker()); @@ -63,6 +69,15 @@ bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { if (!II_fread) II_fread = &Ctx.Idents.get("fread"); + if (!II_fseek) + II_fseek = &Ctx.Idents.get("fseek"); + + if (!II_ftell) + II_ftell = &Ctx.Idents.get("ftell"); + + if (!II_rewind) + II_rewind = &Ctx.Idents.get("rewind"); + if (FD->getIdentifier() == II_fopen) { FOpen(C, CE); return true; @@ -73,6 +88,21 @@ bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { return true; } + if (FD->getIdentifier() == II_fseek) { + FSeek(C, CE); + return true; + } + + if (FD->getIdentifier() == II_ftell) { + FTell(C, CE); + return true; + } + + if (FD->getIdentifier() == II_rewind) { + Rewind(C, CE); + return true; + } + return false; } @@ -96,23 +126,47 @@ void StreamChecker::FOpen(CheckerContext &C, const CallExpr *CE) { void StreamChecker::FRead(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); + if (CheckNullStream(state->getSVal(CE->getArg(3)), state, C)) + return; +} + +void StreamChecker::FSeek(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) + return; +} + +void StreamChecker::FTell(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) + return; +} + +void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + if (CheckNullStream(state->getSVal(CE->getArg(0)), state, C)) + return; +} - // Assume CallAndMessageChecker has been run. - SVal StreamVal = state->getSVal(CE->getArg(3)); +bool StreamChecker::CheckNullStream(SVal SV, const GRState *state, + CheckerContext &C) { + const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV); + if (!DV) + return false; - if (const DefinedSVal *DV = dyn_cast<DefinedSVal>(&StreamVal)) { - ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotNull, *stateNull; - llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotNull, *stateNull; + llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); - if (!stateNotNull && stateNull) { - if (ExplodedNode *N = C.GenerateSink(stateNull)) { - if (!BT_nullfp) - BT_nullfp = new BuiltinBug("NULL stream pointer", + if (!stateNotNull && stateNull) { + if (ExplodedNode *N = C.GenerateSink(stateNull)) { + if (!BT_nullfp) + BT_nullfp = new BuiltinBug("NULL stream pointer", "Stream pointer might be NULL."); - BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N); - C.EmitReport(R); - } + BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N); + C.EmitReport(R); } + return true; } + return false; } diff --git a/clang/test/Analysis/stream.c b/clang/test/Analysis/stream.c index 17876688dd4..f834a6a603c 100644 --- a/clang/test/Analysis/stream.c +++ b/clang/test/Analysis/stream.c @@ -2,11 +2,33 @@ typedef __typeof__(sizeof(int)) size_t; typedef struct _IO_FILE FILE; -FILE *fopen(const char *path, const char *mode); -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +extern FILE *fopen(const char *path, const char *mode); +extern size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +extern int fseek (FILE *__stream, long int __off, int __whence); +extern long int ftell (FILE *__stream); +extern void rewind (FILE *__stream); void f1(void) { FILE *p = fopen("foo", "r"); char buf[1024]; fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL.}} } + +void f2(void) { + FILE *p = fopen("foo", "r"); + fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL.}} +} + +void f3(void) { + FILE *p = fopen("foo", "r"); + ftell(p); // expected-warning {{Stream pointer might be NULL.}} +} + +void f4(void) { + FILE *p = fopen("foo", "r"); + rewind(p); // expected-warning {{Stream pointer might be NULL.}} +} + |

