From c8023788ace75cf0a0417b9b88e643ceebae91e2 Mon Sep 17 00:00:00 2001 From: Zhongxing Xu Date: Wed, 10 Mar 2010 04:58:55 +0000 Subject: [PATCH] Add use-after-free check to MallocChecker. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98136 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Checker/PathSensitive/SVals.h | 3 +++ lib/Checker/MallocChecker.cpp | 24 ++++++++++++++++++++- lib/Checker/SVals.cpp | 19 ++++++++++++++++ test/Analysis/malloc.c | 6 ++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/clang/Checker/PathSensitive/SVals.h b/include/clang/Checker/PathSensitive/SVals.h index 65a8a2c01d..040db831b8 100644 --- a/include/clang/Checker/PathSensitive/SVals.h +++ b/include/clang/Checker/PathSensitive/SVals.h @@ -112,6 +112,9 @@ public: /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData* SymbolRef getAsLocSymbol() const; + /// Get the symbol in the SVal or its base region. + SymbolRef getLocSymbolInBase() const; + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. /// Otherwise return a SymbolRef where 'isValid()' returns false. SymbolRef getAsSymbol() const; diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index 4ff98642e1..a08afc4b79 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -57,17 +57,20 @@ class RegionState {}; class MallocChecker : public CheckerVisitor { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; + BuiltinBug *BT_UseFree; IdentifierInfo *II_malloc, *II_free, *II_realloc; public: MallocChecker() - : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {} + : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), + II_malloc(0), II_free(0), II_realloc(0) {} static void *getTag(); bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper); void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption); + void VisitLocation(CheckerContext &C, const Stmt *S, SVal l); private: void MallocMem(CheckerContext &C, const CallExpr *CE); @@ -339,3 +342,22 @@ const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond, return state; } + +// Check if the location is a freed symbolic region. +void MallocChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { + SymbolRef Sym = l.getLocSymbolInBase(); + if (Sym) { + const RefState *RS = C.getState()->get(Sym); + if (RS) + if (RS->isReleased()) { + ExplodedNode *N = C.GenerateSink(); + if (!BT_UseFree) + BT_UseFree = new BuiltinBug("Use dynamically allocated memory after" + " it is freed."); + + BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(), + N); + C.EmitReport(R); + } + } +} diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp index 28b3fce050..4bfa2cdafb 100644 --- a/lib/Checker/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -70,6 +70,25 @@ SymbolRef SVal::getAsLocSymbol() const { return NULL; } +/// Get the symbol in the SVal or its base region. +SymbolRef SVal::getLocSymbolInBase() const { + const loc::MemRegionVal *X = dyn_cast(this); + + if (!X) + return 0; + + const MemRegion *R = X->getRegion(); + + while (const SubRegion *SR = dyn_cast(R)) { + if (const SymbolicRegion *SymR = dyn_cast(SR)) + return SymR->getSymbol(); + else + R = SR->getSuperRegion(); + } + + return 0; +} + /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. /// Otherwise return 0. // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 3cce1b0d2e..21b6d46a24 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -61,3 +61,9 @@ void pr6069() { void pr6293() { free(0); } + +void f7() { + char *x = (char*) malloc(4); + free(x); + x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}} +} -- 2.40.0