From 8b808d64af8375d77a08d42520c97c7df8e9c3d0 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 11 Feb 2014 02:21:06 +0000 Subject: [PATCH] [analyzer] Inline C++ operator new when c++-inline-allocators is turned on. This will let us stage in the modeling of operator new. The -analyzer-config opton 'c++-inline-allocators' is currently off by default. Patch by Karthik Bhat! llvm-svn: 201122 --- .../StaticAnalyzer/Core/AnalyzerOptions.h | 9 +++++++ .../Core/PathSensitive/ExprEngine.h | 4 +++ .../StaticAnalyzer/Core/AnalyzerOptions.cpp | 6 +++++ clang/lib/StaticAnalyzer/Core/CoreEngine.cpp | 5 ++++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 18 +++++++++---- .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 26 +++++++++++++++++++ .../Core/ExprEngineCallAndReturn.cpp | 2 ++ clang/test/Analysis/inline.cpp | 3 ++- 8 files changed, 67 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 01e89dee3a1a..42b6ca5586aa 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -199,6 +199,9 @@ private: /// \sa mayInlineTemplateFunctions Optional InlineTemplateFunctions; + /// \sa mayInlineCXXAllocator + Optional InlineCXXAllocator; + /// \sa mayInlineCXXContainerCtorsAndDtors Optional InlineCXXContainerCtorsAndDtors; @@ -291,6 +294,12 @@ public: /// accepts the values "true" and "false". bool mayInlineTemplateFunctions(); + /// Returns whether or not allocator call may be considered for inlining. + /// + /// This is controlled by the 'c++-allocator-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXAllocator(); + /// Returns whether or not constructors and destructors of C++ container /// objects may be considered for inlining. /// diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 2699f7d0d767..4ef0a8ba350c 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -421,6 +421,10 @@ public: 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); diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 9dcf58babd27..1bea96e04589 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -134,6 +134,12 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() { /*Default=*/true); } +bool AnalyzerOptions::mayInlineCXXAllocator() { + return getBooleanOption(InlineCXXAllocator, + "c++-allocator-inlining", + /*Default=*/false); +} + bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() { return getBooleanOption(InlineCXXContainerCtorsAndDtors, "c++-container-inlining", diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index b09b2c2ddfab..fa2e78053008 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -532,6 +532,11 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, return; } + if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) { + WList->enqueue(N, Block, Idx+1); + return; + } + // At this point, we know we're processing a normal statement. CFGStmt CS = (*Block)[Idx].castAs(); PostStmt Loc(CS.getStmt(), N->getLocationContext()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 095e09795da3..ba5025b481c2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -553,12 +553,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, 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); + AnalysisManager &AMgr = getAnalysisManager(); + AnalyzerOptions &Opts = AMgr.options; + // TODO: We're not evaluating allocators for all cases just yet as + // we're not handling the return value correctly, which causes false + // positives when the alpha.cplusplus.NewDeleteLeaks check is on. + if (Opts.mayInlineCXXAllocator()) + VisitCXXNewAllocatorCall(NE, Pred, Dst); + else { + 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); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index eba4f94d80e6..fbbc73cc73bf 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -329,6 +329,32 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, *Call, *this); } +void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + CNE->getStartLoc(), + "Error evaluating New Allocator Call"); + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef Call = + CEMgr.getCXXAllocatorCall(CNE, State, LCtx); + + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, + *Call, *this); + + ExplodedNodeSet DstInvalidated; + StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); + for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); + I != E; ++I) + defaultEvalCall(Bldr, *I, *Call); + getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, + *Call, *this); +} + + void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Much of this should eventually migrate to CXXAllocatorCall. diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 863dddaa6f59..e5b46cafab89 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -664,6 +664,8 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, break; } case CE_CXXAllocator: + if (Opts.mayInlineCXXAllocator()) + break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; diff --git a/clang/test/Analysis/inline.cpp b/clang/test/Analysis/inline.cpp index ca126ddf7f38..183df16e124d 100644 --- a/clang/test/Analysis/inline.cpp +++ b/clang/test/Analysis/inline.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify %s void clang_analyzer_eval(bool); void clang_analyzer_checkInlined(bool); @@ -9,6 +9,7 @@ extern "C" void *malloc(size_t); // This is the standard placement new. inline void* operator new(size_t, void* __p) throw() { + clang_analyzer_checkInlined(true);// expected-warning{{TRUE}} return __p; }