diff options
| -rw-r--r-- | clang/include/clang/Checker/PathSensitive/SVals.h | 3 | ||||
| -rw-r--r-- | clang/lib/Checker/MallocChecker.cpp | 24 | ||||
| -rw-r--r-- | clang/lib/Checker/SVals.cpp | 19 | ||||
| -rw-r--r-- | clang/test/Analysis/malloc.c | 6 | 
4 files changed, 51 insertions, 1 deletions
diff --git a/clang/include/clang/Checker/PathSensitive/SVals.h b/clang/include/clang/Checker/PathSensitive/SVals.h index 65a8a2c01df..040db831b8c 100644 --- a/clang/include/clang/Checker/PathSensitive/SVals.h +++ b/clang/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/clang/lib/Checker/MallocChecker.cpp b/clang/lib/Checker/MallocChecker.cpp index 4ff98642e1c..a08afc4b795 100644 --- a/clang/lib/Checker/MallocChecker.cpp +++ b/clang/lib/Checker/MallocChecker.cpp @@ -57,17 +57,20 @@ class RegionState {};  class MallocChecker : public CheckerVisitor<MallocChecker> {    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<RegionState>(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/clang/lib/Checker/SVals.cpp b/clang/lib/Checker/SVals.cpp index 28b3fce050b..4bfa2cdafb4 100644 --- a/clang/lib/Checker/SVals.cpp +++ b/clang/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<loc::MemRegionVal>(this); + +  if (!X) +    return 0; + +  const MemRegion *R = X->getRegion(); + +  while (const SubRegion *SR = dyn_cast<SubRegion>(R)) { +    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(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/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index 3cce1b0d2ef..21b6d46a245 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/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.}} +}  | 

