Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -15,6 +15,7 @@ #include "ClangSACheckers.h" #include "InterCheckerAPI.h" #include "clang/AST/Attr.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -753,6 +754,42 @@ C.addTransition(State); } +static QualType getDeepPointeeType(QualType T) { + QualType Result = T, PointeeType = T->getPointeeType(); + while (!PointeeType.isNull()) { + Result = PointeeType; + PointeeType = PointeeType->getPointeeType(); + } + return Result; +} + +static bool treatUnusedNewEscaped(const CXXNewExpr *NE) { + + const CXXConstructExpr *ConstructE = NE->getConstructExpr(); + if (!ConstructE) + return false; + + if (!NE->getAllocatedType()->getAsCXXRecordDecl()) + return false; + + const CXXConstructorDecl *CtorD = ConstructE->getConstructor(); + + // Iterate over the constructor parameters. + for (const auto *CtorParam : CtorD->params()) { + + QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType(); + if (CtorParamPointeeT.isNull()) + continue; + + CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT); + + if (CtorParamPointeeT->getAsCXXRecordDecl()) + return true; + } + + return false; +} + void MallocChecker::checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { @@ -763,6 +800,10 @@ checkUseAfterFree(Sym, C, *I); if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext())) + return; + + ParentMap &PM = C.getLocationContext()->getParentMap(); + if (!PM.isConsumedExpr(NE) && treatUnusedNewEscaped(NE)) return; ProgramStateRef State = C.getState(); Index: test/Analysis/NewDeleteLeaks-PR19102.cpp =================================================================== --- test/Analysis/NewDeleteLeaks-PR19102.cpp +++ test/Analysis/NewDeleteLeaks-PR19102.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -verify %s + +class A0 {}; + +class A1 { +public: + A1(int); +}; + +struct S{ + int i; +}; + +class A2 { +public: + A2(); + A2(S); + A2(int*); + A2(S*); + A2(S&, int); + A2(int, S**); +}; + +void test() { + new int; // expected-warning@+1 {{Potential memory leak}} + new A0; // expected-warning@+1 {{Potential memory leak}} + new A1(0); // expected-warning@+1 {{Potential memory leak}} + new A2; // expected-warning@+1 {{Potential memory leak}} + S s; + s.i = 1; + S* ps = new S; + new A2(s); // expected-warning@+1 {{Potential memory leak}} + new A2(&(s.i)); // expected-warning@+1 {{Potential memory leak}} + new A2(ps); // no warning + new A2(*ps, 1); // no warning + new A2(1, &ps); // no warning +}