Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -199,6 +199,9 @@ /// \sa mayInlineTemplateFunctions Optional InlineTemplateFunctions; + /// \sa mayInlineCXXAllocator + Optional InlineCXXAllocator; + /// \sa mayInlineCXXContainerCtorsAndDtors Optional InlineCXXContainerCtorsAndDtors; @@ -291,6 +294,12 @@ /// 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. /// Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -421,6 +421,10 @@ 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: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -134,6 +134,12 @@ /*Default=*/true); } +bool AnalyzerOptions::mayInlineCXXAllocator() { + return getBooleanOption(InlineCXXAllocator, + "c++-allocator-inlining", + /*Default=*/false); +} + bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() { return getBooleanOption(InlineCXXContainerCtorsAndDtors, "c++-container-inlining", Index: lib/StaticAnalyzer/Core/CoreEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -532,6 +532,11 @@ 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()); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -553,12 +553,20 @@ 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 when + // alpha.cplusplus.NewDeleteLeaks is check 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); } Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -329,6 +329,32 @@ *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. Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -664,6 +664,8 @@ 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; Index: test/Analysis/inline.cpp =================================================================== --- test/Analysis/inline.cpp +++ 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 @@ // This is the standard placement new. inline void* operator new(size_t, void* __p) throw() { + clang_analyzer_checkInlined(true);// expected-warning{{TRUE}} return __p; }