[PATCH] [Clang SA] Fix double delete warning reported at wrong location.

Karthik Bhat kv.bhat at samsung.com
Thu Dec 19 06:06:29 PST 2013


  Fix Indentation.

Hi jordan_rose,

http://llvm-reviews.chandlerc.com/D2441

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2441?vs=6185&id=6188#toc

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
  lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/NewDelete-checker-test.cpp

Index: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -124,6 +124,7 @@
   void operator=(const CallEvent &) LLVM_DELETED_FUNCTION;
 
 protected:
+  const Stmt *TStmt;
   // This is user data for subclasses.
   const void *Data;
 
@@ -151,7 +152,8 @@
   // DO NOT MAKE PUBLIC
   CallEvent(const CallEvent &Original)
     : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
-      Data(Original.Data), Location(Original.Location), RefCount(0) {}
+      TStmt(Original.TStmt), Data(Original.Data), Location(Original.Location),
+      RefCount(0) {}
 
   /// Copies this CallEvent, with vtable intact, into a new block of memory.
   virtual void cloneTo(void *Dest) const = 0;
@@ -651,7 +653,6 @@
 /// of a full-expression (for temporaries), or as part of a delete.
 class CXXDestructorCall : public CXXInstanceCall {
   friend class CallEventManager;
-
 protected:
   typedef llvm::PointerIntPair<const MemRegion *, 1, bool> DtorDataTy;
 
@@ -667,6 +668,7 @@
                     ProgramStateRef St, const LocationContext *LCtx)
     : CXXInstanceCall(DD, St, LCtx) {
     Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
+    TStmt = Trigger;
     Location = Trigger->getLocEnd();
   }
 
@@ -687,6 +689,10 @@
     return DtorDataTy::getFromOpaqueValue(Data).getInt();
   }
 
+  const Stmt *getTriggerStmt() const {
+    return TStmt;
+  }
+
   virtual Kind getKind() const { return CE_CXXDestructor; }
 
   static bool classof(const CallEvent *CA) {
Index: include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
===================================================================
--- include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -296,6 +296,8 @@
 
   /// \brief Retrieve the statement corresponding to the successor node.
   static const Stmt *getNextStmt(const ExplodedNode *N);
+
+  static const Stmt *getPrevStmt(const ExplodedNode *N);
 };
 
 class PathDiagnosticLocationPair {
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1710,6 +1710,15 @@
       return;
   }
 
+  if (const CXXDestructorCall *DC = dyn_cast<CXXDestructorCall>(&Call)) {
+    if (isa<CXXDeleteExpr>(DC->getTriggerStmt())) {
+      const CXXDeleteExpr *DE =  cast<CXXDeleteExpr>(DC->getTriggerStmt());
+      SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol();
+      if (!Sym || checkUseAfterFree(Sym, C, DE->getArgument()))
+        return;
+    }
+  }
+
   // Check if the callee of a method is deleted.
   if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
     SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===================================================================
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -706,6 +706,33 @@
   return 0;
 }
 
+const Stmt *PathDiagnosticLocation::getPrevStmt(const ExplodedNode *N) {
+  for (N = N->getFirstPred(); N; N = N->getFirstPred()) {
+    if (const Stmt *S = getStmt(N)) {
+      // Check if the statement is '?' or '&&'/'||'.  These are "merges",
+      // not actual statement points.
+      switch (S->getStmtClass()) {
+        case Stmt::ChooseExprClass:
+        case Stmt::BinaryConditionalOperatorClass:
+        case Stmt::ConditionalOperatorClass:
+          continue;
+        case Stmt::BinaryOperatorClass: {
+          BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
+          if (Op == BO_LAnd || Op == BO_LOr)
+            continue;
+          break;
+        }
+        default:
+          break;
+      }
+      // We found the statement, so return it.
+      return S;
+    }
+  }
+
+  return 0;
+}
+
 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
   for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
     if (const Stmt *S = getStmt(N)) {
@@ -739,6 +766,14 @@
   assert(N && "Cannot create a location with a null node.");
   const Stmt *S = getStmt(N);
 
+  // If this is an implicit call find the stmt that triggered it.
+  if (N && !S) {
+    ProgramPoint P = N->getLocation();
+    if (P.getAs<ImplicitCallPoint>()) {
+      S = getPrevStmt(N);
+    }
+  }
+
   if (!S)
     S = getNextStmt(N);
 
Index: test/Analysis/NewDelete-checker-test.cpp
===================================================================
--- test/Analysis/NewDelete-checker-test.cpp
+++ test/Analysis/NewDelete-checker-test.cpp
@@ -338,13 +338,13 @@
 public:
   int *x;
   DerefClass() {}
-  ~DerefClass() {*x = 1;} //expected-warning {{Use of memory after it is freed}}
+  ~DerefClass() {*x = 1;} 
 };
 
 void testDoubleDeleteClassInstance() {
   DerefClass *foo = new DerefClass();
   delete foo;
-  delete foo; // FIXME: We should ideally report warning here instead of inside the destructor.
+  delete foo; //expected-warning {{Use of memory after it is freed}}
 }
 
 class EmptyClass{
@@ -356,5 +356,5 @@
 void testDoubleDeleteEmptyClass() {
   EmptyClass *foo = new EmptyClass();
   delete foo;
-  delete foo;  //expected-warning {{Attempt to free released memory}}
+  delete foo;  //expected-warning {{Use of memory after it is freed}}
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2441.2.patch
Type: text/x-patch
Size: 5573 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131219/81fdf832/attachment.bin>


More information about the cfe-commits mailing list