diff options
| author | Jordan Rose <jordan_rose@apple.com> | 2014-01-13 17:59:19 +0000 |
|---|---|---|
| committer | Jordan Rose <jordan_rose@apple.com> | 2014-01-13 17:59:19 +0000 |
| commit | c9176072e6aae5a7a1a1b17506fe9c35b3399787 (patch) | |
| tree | cda6b2b334ed5debc521e3688289a26405731d3d /clang/lib | |
| parent | 54f6bd59f57150234f5d99d564c57a5c628e7ed6 (diff) | |
| download | bcm5719-llvm-c9176072e6aae5a7a1a1b17506fe9c35b3399787.tar.gz bcm5719-llvm-c9176072e6aae5a7a1a1b17506fe9c35b3399787.zip | |
[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.
llvm-svn: 199123
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Analysis/AnalysisDeclContext.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Analysis/CFG.cpp | 29 | ||||
| -rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 1 |
5 files changed, 49 insertions, 1 deletions
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index 79918a3dbcc..5a9b10775af 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -68,7 +68,8 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addInitializers, bool addTemporaryDtors, bool synthesizeBodies, - bool addStaticInitBranch) + bool addStaticInitBranch, + bool addCXXNewAllocator) : SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; @@ -76,6 +77,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, cfgBuildOptions.AddInitializers = addInitializers; cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; + cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; } void AnalysisDeclContextManager::clear() { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 5837d80b8d3..79966fd887d 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -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, AddStmtChoice asc) { 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::VisitCXXConstructExpr(CXXConstructExpr *C, 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(ASTContext &astContext) const { 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, StmtPrinterHelper &Helper, 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) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 72f8ee1d29d..9864072b722 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1730,6 +1730,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 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. diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ad97801cc0e..095e09795da 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -286,6 +286,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, 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(const CFGImplicitDtor D, 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) { diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 2d3caf9332a..c4297292e97 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -571,6 +571,7 @@ getLocationForCaller(const StackFrameContext *SFC, return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); } case CFGElement::TemporaryDtor: + case CFGElement::NewAllocator: llvm_unreachable("not yet implemented!"); } |

