r199123 - [analyzer] Add a CFG node for the allocator call in a C++ 'new' expression.
Jordan Rose
jordan_rose at apple.com
Mon Jan 13 10:08:44 PST 2014
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 <jordan_rose at apple.com> 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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list