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 | 23d90f90413ff1efd7e4410d28ae2cab99af1fdb (patch) | |
tree | fbf8d504833a72b4a4f290592e1d35a0360fb27c | |
parent | 568e598bf8e89b09a4ebc8c21430e1bd1ba6d11d (diff) |
Add null stream check for more APIs.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106274 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Checker/StreamChecker.cpp | 86 | ||||
-rw-r--r-- | test/Analysis/stream.c | 26 |
2 files changed, 94 insertions, 18 deletions
diff --git a/lib/Checker/StreamChecker.cpp b/lib/Checker/StreamChecker.cpp index 01b7d83042..44919f1339 100644 --- a/lib/Checker/StreamChecker.cpp +++ b/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/test/Analysis/stream.c b/test/Analysis/stream.c index 17876688dd..f834a6a603 100644 --- a/test/Analysis/stream.c +++ b/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.}} +} + |