Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1458,11 +1458,16 @@ // If this is an assignment expression, we can track the value // being assigned. - if (Optional P = Succ->getLocationAs()) + if (Optional P = Succ->getLocationAs()) { if (const BinaryOperator *BO = P->getStmtAs()) if (BO->isAssignmentOp()) InitE = BO->getRHS(); + if (const CXXConstructExpr *CE = P->getStmtAs()) { + InitE = CE; + } + } + // If this is a call entry, the variable should be a parameter. // FIXME: Handle CXXThisRegion as well. (This is not a priority because // 'this' should never be NULL, but this visitor isn't just for NULL and @@ -2397,33 +2402,92 @@ ProgramStateRef RVState = RVNode->getState(); SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext()); - const auto *BO = dyn_cast(E); - - if (!BO || !BO->isMultiplicativeOp() || !V.isZeroConstant()) - return {}; - SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext()); - SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext()); - - // Track both LHS and RHS of a multiplication. Tracker::Result CombinedResult; Tracker &Parent = getParentTracker(); - - const auto track = [&CombinedResult, &Parent, ExprNode, Opts](Expr *Inner) { + const auto track = [&CombinedResult, &Parent, ExprNode, + Opts](const Expr *Inner) { CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts)); }; - if (BO->getOpcode() == BO_Mul) { - if (LHSV.isZeroConstant()) - track(BO->getLHS()); - if (RHSV.isZeroConstant()) - track(BO->getRHS()); - } else { // Track only the LHS of a division or a modulo. - if (LHSV.isZeroConstant()) - track(BO->getLHS()); + const auto *BO = dyn_cast(E); + if (BO && BO->isMultiplicativeOp() && V.isZeroConstant()) { + SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext()); + SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext()); + + // Track both LHS and RHS of a multiplication. + if (BO->getOpcode() == BO_Mul) { + if (LHSV.isZeroConstant()) + track(BO->getLHS()); + if (RHSV.isZeroConstant()) + track(BO->getRHS()); + } else { // Track only the LHS of a division or a modulo. + if (LHSV.isZeroConstant()) + track(BO->getLHS()); + } + + return CombinedResult; + } + + // This can help producing more detailed warning messages. + if (const auto *ILE = dyn_cast(E)) { + + // FIXME: We can't reason about the individual members of + // the initializer list. What we know is that if it only has + // 1 element, we want to track that element for sure. + // + // E.g.: + // struct S { int *p1, *p2; }; + // + // void foo() { + // int *x = nullptr, *y = nullptr; + // S s{x, y}; <-- We want to track 'x' here and not 'y'. + // At this point the tracked region is 's', + // so the analyzer doesn't know which + // element of the initializer list to track. + // As a result we either track all of them + // or none. + // S s2 = s; + // int i = *s.p1; + // } + if (ILE->getNumInits() == 1) { + track(ILE->getInit(0)); + + return CombinedResult; + } + } + + if (const auto *CE = dyn_cast(E)) { + + // FIXME: We can't reason about the individual arguments of + // the constructor. What we know is that if it only has + // 1 element, we want to track that element for sure. + // + // E.g.: + // struct S { + // int *p1, *p2; + // S(int *a, int *b) : p1(a), p2(b) {} + // }; + // + // void foo() { + // int *x = nullptr, *y = nullptr; + // S s = S(x, y); <-- We want to track 'x' here and not 'y'. + // At this point the tracked region is 's', + // so the analyzer doesn't know which + // argument of the constructor to track. + // As a result we either track all of them + // or none. + // S s2 = s; + // int i = *s2.p1; + // } + if (CE->getNumArgs() == 1) { + track(CE->getArg(0)); + + return CombinedResult; + } } - return CombinedResult; + return {}; } }; Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -693,6 +693,7 @@ void test_smart_ptr_leak() { OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}} + // expected-note@-1{{'obj' initialized here}} { OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr'}} // expected-note@-1{{Returning from constructor for 'smart_ptr'}}