Richard^2, just wanted to double-check that it makes sense not to turn this on for the analysis-based warnings at this time.
Jordan On Jan 13, 2014, at 9:59 , Jordan Rose <[email protected]> wrote: > Author: jrose > Date: Mon Jan 13 11:59:19 2014 > New Revision: 199123 > > URL: http://llvm.org/viewvc/llvm-project?rev=199123&view=rev > Log: > [analyzer] Add a CFG node for the allocator call in a C++ 'new' expression. > > In an expression like "new (a, b) Foo(x, y)", two things happen: > - Memory is allocated by calling a function named 'operator new'. > - The memory is initialized using the constructor for 'Foo'. > > Currently the analyzer only models the second event, though it has special > cases for both the default and placement forms of operator new. This patch > is the first step towards properly modeling both events: it changes the CFG > so that the above expression now generates the following elements. > > 1. a > 2. b > 3. (CFGNewAllocator) > 4. x > 5. y > 6. Foo::Foo > > The analyzer currently ignores the CFGNewAllocator element, but the next > step is to treat that as a call like any other. > > The CFGNewAllocator element is not added to the CFG for analysis-based > warnings, since none of them take advantage of it yet. > > Modified: > cfe/trunk/include/clang/Analysis/AnalysisContext.h > cfe/trunk/include/clang/Analysis/CFG.h > cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h > cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp > cfe/trunk/lib/Analysis/CFG.cpp > cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp > cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp > cfe/trunk/test/Analysis/cfg.cpp > > Modified: cfe/trunk/include/clang/Analysis/AnalysisContext.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisContext.h?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Analysis/AnalysisContext.h (original) > +++ cfe/trunk/include/clang/Analysis/AnalysisContext.h Mon Jan 13 11:59:19 > 2014 > @@ -409,7 +409,8 @@ public: > bool addInitializers = false, > bool addTemporaryDtors = false, > bool synthesizeBodies = false, > - bool addStaticInitBranches = false); > + bool addStaticInitBranches = false, > + bool addCXXNewAllocator = true); > > ~AnalysisDeclContextManager(); > > > Modified: cfe/trunk/include/clang/Analysis/CFG.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Analysis/CFG.h (original) > +++ cfe/trunk/include/clang/Analysis/CFG.h Mon Jan 13 11:59:19 2014 > @@ -46,6 +46,7 @@ namespace clang { > class ASTContext; > class CXXRecordDecl; > class CXXDeleteExpr; > + class CXXNewExpr; > > /// CFGElement - Represents a top-level expression in a basic block. > class CFGElement { > @@ -54,6 +55,7 @@ public: > // main kind > Statement, > Initializer, > + NewAllocator, > // dtor kind > AutomaticObjectDtor, > DeleteDtor, > @@ -71,7 +73,9 @@ protected: > > 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 @@ private: > } > }; > > +/// 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 @@ public: > 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 @@ public: > bool AddImplicitDtors; > bool AddTemporaryDtors; > bool AddStaticInitBranches; > + bool AddCXXNewAllocator; > > bool alwaysAdd(const Stmt *stmt) const { > return alwaysAddMask[stmt->getStmtClass()]; > @@ -659,7 +688,8 @@ public: > ,AddInitializers(false) > ,AddImplicitDtors(false) > ,AddTemporaryDtors(false) > - ,AddStaticInitBranches(false) {} > + ,AddStaticInitBranches(false) > + ,AddCXXNewAllocator(false) {} > }; > > /// \brief Provides a custom implementation of the iterator class to have > the > > Modified: > cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h > (original) > +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h > Mon Jan 13 11:59:19 2014 > @@ -201,7 +201,9 @@ public: > > 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); > > Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original) > +++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Mon Jan 13 11:59:19 2014 > @@ -68,7 +68,8 @@ AnalysisDeclContextManager::AnalysisDecl > bool addInitializers, > bool addTemporaryDtors, > bool synthesizeBodies, > - bool > addStaticInitBranch) > + bool > addStaticInitBranch, > + bool > addCXXNewAllocator) > : SynthesizeBodies(synthesizeBodies) > { > cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; > @@ -76,6 +77,7 @@ AnalysisDeclContextManager::AnalysisDecl > cfgBuildOptions.AddInitializers = addInitializers; > cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; > cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; > + cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; > } > > void AnalysisDeclContextManager::clear() { > > Modified: cfe/trunk/lib/Analysis/CFG.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/lib/Analysis/CFG.cpp (original) > +++ cfe/trunk/lib/Analysis/CFG.cpp Mon Jan 13 11:59:19 2014 > @@ -363,6 +363,7 @@ private: > 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 @@ private: > 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 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, Ad > 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,6 +3131,22 @@ CFGBlock *CFGBuilder::VisitCXXConstructE > 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) { > @@ -3426,6 +3449,7 @@ CFGImplicitDtor::getDestructorDecl(ASTCo > 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 @@ static void print_elem(raw_ostream &OS, > 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) > > Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original) > +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Mon Jan 13 11:59:19 2014 > @@ -1730,6 +1730,7 @@ AnalysisBasedWarnings::IssueWarnings(sem > AC.getCFGBuildOptions().AddInitializers = true; > AC.getCFGBuildOptions().AddImplicitDtors = true; > AC.getCFGBuildOptions().AddTemporaryDtors = true; > + AC.getCFGBuildOptions().AddCXXNewAllocator = false; > > // Force that certain expressions appear as CFGElements in the CFG. This > // is used to speed up various analyses. > > Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) > +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Jan 13 11:59:19 2014 > @@ -286,6 +286,10 @@ void ExprEngine::processCFGElement(const > 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 @@ void ExprEngine::ProcessImplicitDtor(con > 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) { > > Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original) > +++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Mon Jan 13 11:59:19 > 2014 > @@ -571,6 +571,7 @@ getLocationForCaller(const StackFrameCon > return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); > } > case CFGElement::TemporaryDtor: > + case CFGElement::NewAllocator: > llvm_unreachable("not yet implemented!"); > } > > > Modified: cfe/trunk/test/Analysis/cfg.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg.cpp?rev=199123&r1=199122&r2=199123&view=diff > ============================================================================== > --- cfe/trunk/test/Analysis/cfg.cpp (original) > +++ cfe/trunk/test/Analysis/cfg.cpp Mon Jan 13 11:59:19 2014 > @@ -110,13 +110,14 @@ public: > // 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 @@ void test_deletedtor() { > // 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 @@ int test_enum_with_extension_default(enu > 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]; > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
