From 8b662704dc68e56e5df3763bb6816f0a07930fbb Mon Sep 17 00:00:00 2001 From: Anton Yartsev Date: Thu, 28 Mar 2013 16:10:38 +0000 Subject: [analyzer] For now assume all standard global 'operator new' functions allocate memory in heap. + Improved test coverage for cplusplus.NewDelete checker. llvm-svn: 178244 --- .../lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 9 ++++--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 30 ++++++++++++++++++---- 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'clang/lib/StaticAnalyzer') diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 068f9ce822a..25984458665 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -457,6 +457,10 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const return false; } +// Tells if the callee is one of the following: +// 1) A global non-placement new/delete operator function. +// 2) A global placement operator function with the single placement argument +// of type std::nothrow_t. bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const { if (!FD) @@ -467,9 +471,8 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, Kind != OO_Delete && Kind != OO_Array_Delete) return false; - // Skip custom new operators. - if (!FD->isImplicit() && - !C.getSourceManager().isInSystemHeader(FD->getLocStart())) + // Skip all operator new/delete methods. + if (isa(FD)) return false; // Return true if tested operator is a standard placement nothrow operator. diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 0fedf255d6f..c1dd6b22209 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -278,11 +278,32 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); - DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, - CNE->getType(), - blockCount); - ProgramStateRef State = Pred->getState(); + DefinedOrUnknownSVal symVal = UnknownVal(); + FunctionDecl *FD = CNE->getOperatorNew(); + + bool IsStandardGlobalOpNewFunction = false; + if (FD && !isa(FD) && !FD->isVariadic()) { + if (FD->getNumParams() == 2) { + QualType T = FD->getParamDecl(1)->getType(); + if (const IdentifierInfo *II = T.getBaseTypeIdentifier()) + // NoThrow placement new behaves as a standard new. + IsStandardGlobalOpNewFunction = II->getName().equals("nothrow_t"); + } + else + // Placement forms are considered non-standard. + IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1); + } + + // We assume all standard global 'operator new' functions allocate memory in + // heap. We realize this is an approximation that might not correctly model + // a custom global allocator. + if (IsStandardGlobalOpNewFunction) + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); + else + symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(), + blockCount); + ProgramStateRef State = Pred->getState(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef Call = CEMgr.getCXXAllocatorCall(CNE, State, LCtx); @@ -296,7 +317,6 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // is not declared as non-throwing, failures /must/ be signalled by // exceptions, and thus the return value will never be NULL. // C++11 [basic.stc.dynamic.allocation]p3. - FunctionDecl *FD = CNE->getOperatorNew(); if (FD && getContext().getLangOpts().CXXExceptions) { QualType Ty = FD->getType(); if (const FunctionProtoType *ProtoType = Ty->getAs()) -- cgit v1.2.3