Hi Jordan,
  Modified CFG to handle placement new arguments properly in VisitCXXNewExpr.
  Since we have not handled this new CFGElement(CFGNewAllocator) completly in 
ExprEngine there are few failures as analysis stops after it encounters a 
CFGNewAllocator node.
  Is there a way so skip this node and continue analysis in ExprEngine so that 
there are no extra failures till we complete handling CFGNewAllocator in 
ExprEngine?
  I tried few things but it doesn't seem to work. It would be great if you 
could give some inputs here so that this checkin doesn't introduce regression.

  Thanks
  Karthik

Hi jordan_rose,

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

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

Files:
  include/clang/Analysis/CFG.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  test/Analysis/cfg.cpp
  lib/Analysis/CFG.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -45,6 +45,7 @@
   class ASTContext;
   class CXXRecordDecl;
   class CXXDeleteExpr;
+  class CXXNewExpr;
 
 /// CFGElement - Represents a top-level expression in a basic block.
 class CFGElement {
@@ -53,6 +54,7 @@
     // main kind
     Statement,
     Initializer,
+    NewAllocator,
     // dtor kind
     AutomaticObjectDtor,
     DeleteDtor,
@@ -141,6 +143,24 @@
   }
 };
 
+class CFGNewAllocator : public CFGElement {
+public:
+  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 {
@@ -576,6 +596,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);
   }
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);
@@ -420,6 +422,9 @@
                           const Stmt *S, bool IsBaseDtor,
                           ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
+  void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNode *Pred,
+                                ExplodedNodeSet &Dst);
+
   void VisitCXXNewExpr(const CXXNewExpr *CNE, 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
+// 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)]
@@ -129,14 +130,15 @@
 // CHECK: [B2 (ENTRY)]
 // 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:   1: CFGNewAllocator
+// CHECK-NEXT:   2: 5
+// CHECK-NEXT:   3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   4: new A {{\[\[}}B1.2]]
+// 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,43 @@
     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
+// 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);
+
+class MyClass {
+public:
+  MyClass() {}
+  ~MyClass() {}
+};
+
+void test_placement_new() {
+  int buffer[16];
+  MyClass* obj = new (buffer) MyClass();
+}
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);
 
@@ -3120,11 +3127,27 @@
                                             AddStmtChoice asc) {
   autoCreateBlock();
   appendStmt(Block, C);
-
   return VisitChildren(C);
 }
 
+CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
+                                      AddStmtChoice asc) {
 
+  autoCreateBlock();
+  appendStmt(Block, NE);
+  if (NE->getInitializer())
+    Block = VisitStmt(NE->getInitializer(), asc);
+  if (NE->isArray())
+    Block = VisitStmt(NE->getArraySize(), asc);
+  appendNewAllocator(Block, NE);
+  if (NE->getNumPlacementArgs() > 0) {
+    for (int i=0;i<NE->getNumPlacementArgs();++i) {
+      Block = VisitStmt(NE->getPlacementArg(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,8 @@
     OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
     OS << " (Implicit destructor)\n";
 
+  } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
+    OS << "CFGNewAllocator\n";
   } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
     const CXXRecordDecl *RD = DE->getCXXRecordDecl();
     if (!RD)
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,9 @@
     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 +550,13 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
+                                     ExplodedNode *Pred) {
+  ExplodedNodeSet Dst;
+  VisitCXXNewAllocatorCall(NE,Pred,Dst);
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
                                          ExplodedNode *Pred,
                                          ExplodedNodeSet &Dst) {
Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -329,13 +329,19 @@
                                              *Call, *this);
 }
 
+void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNode *Pred,
+                                          ExplodedNodeSet &Dst) {
+  //TODO: Handle VisitCXXNewAllocatorExpr
+}
+
 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
                                    ExplodedNodeSet &Dst) {
+
   // FIXME: Much of this should eventually migrate to CXXAllocatorCall.
   // Also, we need to decide how allocators actually work -- they're not
   // really part of the CXXNewExpr because they happen BEFORE the
   // CXXConstructExpr subexpression. See PR12014 for some discussion.
-  
+
   unsigned blockCount = currBldrCtx->blockCount();
   const LocationContext *LCtx = Pred->getLocationContext();
   DefinedOrUnknownSVal symVal = UnknownVal();
@@ -354,13 +360,13 @@
       IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1);
   }
 
-  // We assume all standard global 'operator new' functions allocate memory in 
-  // heap. We realize this is an approximation that might not correctly model 
+  // We assume all standard global 'operator new' functions allocate memory in
+  // heap. We realize this is an approximation that might not correctly model
   // a custom global allocator.
   if (IsStandardGlobalOpNewFunction)
     symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
   else
-    symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), 
+    symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(),
                                           blockCount);
 
   ProgramStateRef State = Pred->getState();
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to