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