Hi Jordan,
  Implemented review comments. Added  flag in 
CFG::BuildOptions(AddCXXNewAllocator) enabled by default currently which adds 
CFGNewAllocator node.
  Please let me know if this looks ok. Passes regression in debug and release 
mode.
  Thanks
  Karthik Bhat

Hi jordan_rose,

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

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2423?vs=6405&id=6429#toc

Files:
  lib/Analysis/CFG.cpp
  lib/Analysis/AnalysisDeclContext.cpp
  lib/Sema/AnalysisBasedWarnings.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/Analysis/cfg.cpp
  include/clang/Analysis/CFG.h
  include/clang/Analysis/AnalysisContext.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -363,6 +363,7 @@
                                       AddStmtChoice asc);
   CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
   CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
+  CFGBlock *VisitCXXNewExpr(CXXNewExpr *DE, AddStmtChoice asc);
   CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
   CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
   CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
@@ -459,6 +460,9 @@
   void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
     B->appendInitializer(I, cfg->getBumpVectorContext());
   }
+  void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
+    B->appendNewAllocator(NE, cfg->getBumpVectorContext());
+  }
   void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) {
     B->appendBaseDtor(BS, cfg->getBumpVectorContext());
   }
@@ -1122,6 +1126,9 @@
     case Stmt::CXXConstructExprClass:
       return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
 
+    case Stmt::CXXNewExprClass:
+      return VisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
+
     case Stmt::CXXDeleteExprClass:
       return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
 
@@ -3124,7 +3131,23 @@
   return VisitChildren(C);
 }
 
+CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
+                                      AddStmtChoice asc) {
 
+  autoCreateBlock();
+  appendStmt(Block, NE);
+  if (NE->getInitializer())
+    Block = VisitStmt(NE->getInitializer(), asc);
+  if (BuildOpts.AddCXXNewAllocator)
+    appendNewAllocator(Block, NE);
+  if (NE->isArray())
+    Block = VisitStmt(NE->getArraySize(), asc);
+  for (CXXNewExpr::arg_iterator I = NE->placement_arg_begin(),
+       E = NE->placement_arg_end(); I != E; ++I)
+    Block = VisitStmt(*I, asc);
+  return Block;
+}
+
 CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
                                          AddStmtChoice asc) {
   autoCreateBlock();
@@ -3426,6 +3449,7 @@
   switch (getKind()) {
     case CFGElement::Statement:
     case CFGElement::Initializer:
+    case CFGElement::NewAllocator:
       llvm_unreachable("getDestructorDecl should only be used with "
                        "ImplicitDtors");
     case CFGElement::AutomaticObjectDtor: {
@@ -3789,6 +3813,11 @@
     OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
     OS << " (Implicit destructor)\n";
 
+  } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
+    OS << "CFGNewAllocator(";
+    if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
+      AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
+    OS << ")\n";
   } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
     const CXXRecordDecl *RD = DE->getCXXRecordDecl();
     if (!RD)
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -68,7 +68,8 @@
                                                        bool addInitializers,
                                                        bool addTemporaryDtors,
                                                        bool synthesizeBodies,
-                                                       bool addStaticInitBranch)
+                                                       bool addStaticInitBranch,
+                                                       bool addCXXNewAllocator)
   : SynthesizeBodies(synthesizeBodies)
 {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
@@ -76,6 +77,7 @@
   cfgBuildOptions.AddInitializers = addInitializers;
   cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
   cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
+  cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
 }
 
 void AnalysisDeclContextManager::clear() {
Index: lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- lib/Sema/AnalysisBasedWarnings.cpp
+++ lib/Sema/AnalysisBasedWarnings.cpp
@@ -1730,6 +1730,7 @@
   AC.getCFGBuildOptions().AddInitializers = true;
   AC.getCFGBuildOptions().AddImplicitDtors = true;
   AC.getCFGBuildOptions().AddTemporaryDtors = true;
+  AC.getCFGBuildOptions().AddCXXNewAllocator = true;
 
   // Force that certain expressions appear as CFGElements in the CFG.  This
   // is used to speed up various analyses.
Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===================================================================
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -571,6 +571,7 @@
     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
   }
   case CFGElement::TemporaryDtor:
+  case CFGElement::NewAllocator:
     llvm_unreachable("not yet implemented!");
   }
 
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -286,6 +286,10 @@
     case CFGElement::Initializer:
       ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
       return;
+    case CFGElement::NewAllocator:
+      ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(),
+                          Pred);
+      return;
     case CFGElement::AutomaticObjectDtor:
     case CFGElement::DeleteDtor:
     case CFGElement::BaseDtor:
@@ -547,6 +551,17 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
+                                     ExplodedNode *Pred) {
+  //TODO: Implement VisitCXXNewAllocatorCall
+  ExplodedNodeSet Dst;
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+  const LocationContext *LCtx = Pred->getLocationContext();
+  PostImplicitCall PP(NE->getOperatorNew(), NE->getLocStart(), LCtx);
+  Bldr.generateNode(PP, Pred->getState(), Pred);
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
                                          ExplodedNode *Pred,
                                          ExplodedNodeSet &Dst) {
Index: test/Analysis/cfg.cpp
===================================================================
--- test/Analysis/cfg.cpp
+++ test/Analysis/cfg.cpp
@@ -110,13 +110,14 @@
 // CHECK: [B2 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B1
 // CHECK: [B1]
-// CHECK-NEXT:   1:  (CXXConstructExpr, class A)
-// CHECK-NEXT:   2: new A([B1.1])
-// CHECK-NEXT:   3: A *a = new A();
-// CHECK-NEXT:   4: a
-// CHECK-NEXT:   5: [B1.4] (ImplicitCastExpr, LValueToRValue, class A *)
-// CHECK-NEXT:   6: [B1.5]->~A() (Implicit destructor)
-// CHECK-NEXT:   7: delete [B1.5]
+// CHECK-NEXT:   1:  CFGNewAllocator(A *)
+// CHECK-NEXT:   2:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   3: new A([B1.2])
+// CHECK-NEXT:   4: A *a = new A();
+// CHECK-NEXT:   5: a
+// CHECK-NEXT:   6: [B1.5] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT:   7: [B1.6]->~A() (Implicit destructor)
+// CHECK-NEXT:   8: delete [B1.6]
 // CHECK-NEXT:   Preds (1): B2
 // CHECK-NEXT:   Succs (1): B0
 // CHECK: [B0 (EXIT)]
@@ -130,13 +131,14 @@
 // CHECK-NEXT:   Succs (1): B1
 // CHECK: [B1]
 // CHECK-NEXT:   1: 5
-// CHECK-NEXT:   2:  (CXXConstructExpr, class A)
-// CHECK-NEXT:   3: new A {{\[\[}}B1.1]]
-// CHECK-NEXT:   4: A *a = new A [5];
-// CHECK-NEXT:   5: a
-// CHECK-NEXT:   6: [B1.5] (ImplicitCastExpr, LValueToRValue, class A *)
-// CHECK-NEXT:   7: [B1.6]->~A() (Implicit destructor)
-// CHECK-NEXT:   8: delete [] [B1.6]
+// CHECK-NEXT:   2: CFGNewAllocator(A *)
+// CHECK-NEXT:   3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   4: new A {{\[\[}}B1.1]]
+// CHECK-NEXT:   5: A *a = new A [5];
+// CHECK-NEXT:   6: a
+// CHECK-NEXT:   7: [B1.6] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT:   8: [B1.7]->~A() (Implicit destructor)
+// CHECK-NEXT:   9: delete [] [B1.7]
 // CHECK-NEXT:   Preds (1): B2
 // CHECK-NEXT:   Succs (1): B0
 // CHECK: [B0 (EXIT)]
@@ -308,4 +310,65 @@
     default: x = 4; break;
   }
   return x;
-}
\ No newline at end of file
+}
+
+
+// CHECK:  [B1 (ENTRY)]
+// CHECK-NEXT:  Succs (1): B0
+// CHECK:  [B0 (EXIT)]
+// CHECK-NEXT:  Preds (1): B1
+// CHECK:  [B1 (ENTRY)]
+// CHECK-NEXT:  Succs (1): B0
+// CHECK:  [B0 (EXIT)]
+// CHECK-NEXT:  Preds (1): B1
+// CHECK:  [B2 (ENTRY)]
+// CHECK-NEXT:  Succs (1): B1
+// CHECK:  [B1]
+// CHECK-NEXT:  1: int buffer[16];
+// CHECK-NEXT:  2: buffer
+// CHECK-NEXT:  3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *)
+// CHECK-NEXT:  4: [B1.3] (ImplicitCastExpr, BitCast, void *)
+// CHECK-NEXT:  5: CFGNewAllocator(MyClass *)
+// CHECK-NEXT:  6:  (CXXConstructExpr, class MyClass)
+// CHECK-NEXT:  7: new ([B1.4]) MyClass([B1.6])
+// CHECK-NEXT:  8: MyClass *obj = new (buffer) MyClass();
+// CHECK-NEXT:  Preds (1): B2
+// CHECK-NEXT:  Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT:  Preds (1): B1
+
+extern void* operator new (unsigned long sz, void* v);
+extern void* operator new[] (unsigned long sz, void* ptr);
+
+class MyClass {
+public:
+  MyClass() {}
+  ~MyClass() {}
+};
+
+void test_placement_new() {
+  int buffer[16];
+  MyClass* obj = new (buffer) MyClass();
+}
+
+// CHECK:  [B2 (ENTRY)]
+// CHECK-NEXT:  Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT:  1: int buffer[16];
+// CHECK-NEXT:  2: buffer
+// CHECK-NEXT:  3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *)
+// CHECK-NEXT:  4: [B1.3] (ImplicitCastExpr, BitCast, void *)
+// CHECK-NEXT:  5: 5
+// CHECK-NEXT:  6: CFGNewAllocator(MyClass *)
+// CHECK-NEXT:  7:  (CXXConstructExpr, class MyClass)
+// CHECK-NEXT:  8: new ([B1.4]) MyClass {{\[\[}}B1.5]]
+// CHECK-NEXT:  9: MyClass *obj = new (buffer) MyClass [5];
+// CHECK-NEXT:  Preds (1): B2
+// CHECK-NEXT:  Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT:  Preds (1): B1
+
+void test_placement_new_array() {
+  int buffer[16];
+  MyClass* obj = new (buffer) MyClass[5];
+}
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -46,6 +46,7 @@
   class ASTContext;
   class CXXRecordDecl;
   class CXXDeleteExpr;
+  class CXXNewExpr;
 
 /// CFGElement - Represents a top-level expression in a basic block.
 class CFGElement {
@@ -54,6 +55,7 @@
     // main kind
     Statement,
     Initializer,
+    NewAllocator,
     // dtor kind
     AutomaticObjectDtor,
     DeleteDtor,
@@ -71,7 +73,9 @@
 
   CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0)
     : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
-      Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
+      Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
+    assert(getKind() == kind);
+  }
 
   CFGElement() {}
 public:
@@ -142,6 +146,25 @@
   }
 };
 
+/// CFGNewAllocator - Represents C++ allocator call.
+class CFGNewAllocator : public CFGElement {
+public:
+  explicit CFGNewAllocator(const CXXNewExpr *S)
+    : CFGElement(NewAllocator, S) {}
+
+  // Get the new expression.
+  const CXXNewExpr *getAllocatorExpr() const {
+    return static_cast<CXXNewExpr *>(Data1.getPointer());
+  }
+
+private:
+  friend class CFGElement;
+  CFGNewAllocator() {}
+  static bool isKind(const CFGElement &elem) {
+    return elem.getKind() == NewAllocator;
+  }
+};
+
 /// CFGImplicitDtor - Represents C++ object destructor implicitly generated
 /// by compiler on various occasions.
 class CFGImplicitDtor : public CFGElement {
@@ -580,6 +603,11 @@
     Elements.push_back(CFGInitializer(initializer), C);
   }
 
+  void appendNewAllocator(CXXNewExpr *NE,
+                          BumpVectorContext &C) {
+    Elements.push_back(CFGNewAllocator(NE), C);
+  }
+
   void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
     Elements.push_back(CFGBaseDtor(BS), C);
   }
@@ -638,6 +666,7 @@
     bool AddImplicitDtors;
     bool AddTemporaryDtors;
     bool AddStaticInitBranches;
+    bool AddCXXNewAllocator;
 
     bool alwaysAdd(const Stmt *stmt) const {
       return alwaysAddMask[stmt->getStmtClass()];
@@ -659,7 +688,8 @@
       ,AddInitializers(false)
       ,AddImplicitDtors(false)
       ,AddTemporaryDtors(false)
-      ,AddStaticInitBranches(false) {}
+      ,AddStaticInitBranches(false)
+      ,AddCXXNewAllocator(true) {}
   };
 
   /// \brief Provides a custom implementation of the iterator class to have the
Index: include/clang/Analysis/AnalysisContext.h
===================================================================
--- include/clang/Analysis/AnalysisContext.h
+++ include/clang/Analysis/AnalysisContext.h
@@ -409,7 +409,8 @@
                              bool addInitializers = false,
                              bool addTemporaryDtors = false,
                              bool synthesizeBodies = false,
-                             bool addStaticInitBranches = false);
+                             bool addStaticInitBranches = false,
+                             bool addCXXNewAllocator =  true);
 
   ~AnalysisDeclContextManager();
 
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -201,7 +201,9 @@
 
   void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
 
-  void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, 
+  void ProcessNewAllocator(const CXXNewExpr *NE, ExplodedNode *Pred);
+
+  void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
                                ExplodedNode *Pred, ExplodedNodeSet &Dst);
   void ProcessDeleteDtor(const CFGDeleteDtor D,
                          ExplodedNode *Pred, ExplodedNodeSet &Dst);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to