diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -51,6 +51,7 @@ struct EvalCallOptions; class MemRegion; struct NodeBuilderContext; +class NodeBuilder; class ObjCMethodCall; class RegionAndSymbolInvalidationTraits; class SVal; @@ -439,7 +440,8 @@ /// Warning: Currently, the CallEvent MUST come from a CallExpr! void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &CE, ExprEngine &Eng, - const EvalCallOptions &CallOpts); + const EvalCallOptions &CallOpts, + llvm::Optional B); /// Run checkers for the entire Translation Unit. void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -654,12 +654,14 @@ const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, - const EvalCallOptions &CallOpts) { + const EvalCallOptions &CallOpts, + llvm::Optional B) { for (auto *const Pred : Src) { bool anyEvaluated = false; ExplodedNodeSet checkDst; - NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); + auto CurrentNodeBldr = + B ? B.getValue() : NodeBuilder(Pred, checkDst, Eng.getBuilderContext()); // Check if any of the EvalCall callbacks can evaluate the call. for (const auto &EvalCallChecker : EvalCallCheckers) { @@ -672,7 +674,7 @@ { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. - CheckerContext C(B, Eng, Pred, L); + CheckerContext C(CurrentNodeBldr, Eng, Pred, L); evaluated = EvalCallChecker(Call, C); } assert(!(evaluated && anyEvaluated) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -616,7 +616,7 @@ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this, - CallOpts); + CallOpts, Bldr); } // If the CFG was constructed without elements for temporary destructors diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -583,8 +583,8 @@ // to see if the can evaluate the function call, and get a callback at // defaultEvalCall if all of them fail. ExplodedNodeSet dstCallEvaluated; - getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, - Call, *this, EvalCallOptions()); + getCheckerManager().runCheckersForEvalCall( + dstCallEvaluated, dstPreVisit, Call, *this, EvalCallOptions(), None); // If there were other constructors called for object-type arguments // of this call, clean them up. diff --git a/clang/test/Analysis/smart-ptr-text-output.cpp b/clang/test/Analysis/smart-ptr-text-output.cpp --- a/clang/test/Analysis/smart-ptr-text-output.cpp +++ b/clang/test/Analysis/smart-ptr-text-output.cpp @@ -36,14 +36,14 @@ } void derefAfterRelease() { - std::unique_ptr P(new A()); + std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}} P.release(); // expected-note {{Smart pointer 'P' is released and set to null}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} // expected-note@-1{{Dereference of null smart pointer 'P'}} } void derefAfterReset() { - std::unique_ptr P(new A()); + std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}} P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} // expected-note@-1{{Dereference of null smart pointer 'P'}} @@ -51,7 +51,7 @@ void derefAfterResetWithNull() { A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} - std::unique_ptr P(new A()); + std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}} P.reset(NullInnerPtr); // expected-note {{Smart pointer 'P' reset using a null value}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} // expected-note@-1{{Dereference of null smart pointer 'P'}} @@ -67,7 +67,7 @@ } void derefOnSwappedNullPtr() { - std::unique_ptr P(new A()); + std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}} std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} P.swap(PNull); // expected-note {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} PNull->foo(); // No warning. @@ -77,13 +77,11 @@ // FIXME: Fix this test when "std::swap" is modeled seperately. void derefOnStdSwappedNullPtr() { - std::unique_ptr P; + std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}} std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} // expected-note@-1 {{Calling 'swap'}} // expected-note@-2 {{Returning from 'swap'}} - PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} - // expected-note@-1{{Dereference of null smart pointer 'PNull'}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} // expected-note@-1{{Dereference of null smart pointer 'P'}} } diff --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp --- a/clang/test/Analysis/smart-ptr.cpp +++ b/clang/test/Analysis/smart-ptr.cpp @@ -41,6 +41,7 @@ void derefAfterValidCtr() { std::unique_ptr P(new A()); + clang_analyzer_numTimesReached(); // expected-warning {{1}} P->foo(); // No warning. } @@ -50,17 +51,20 @@ void derefAfterDefaultCtr() { std::unique_ptr P; + clang_analyzer_numTimesReached(); // expected-warning {{1}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterCtrWithNull() { std::unique_ptr P(nullptr); + clang_analyzer_numTimesReached(); // expected-warning {{1}} *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } void derefAfterCtrWithNullVariable() { A *InnerPtr = nullptr; std::unique_ptr P(InnerPtr); + clang_analyzer_numTimesReached(); // expected-warning {{1}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } @@ -87,6 +91,7 @@ void derefAfterResetWithNonNull() { std::unique_ptr P; P.reset(new A()); + clang_analyzer_numTimesReached(); // expected-warning {{1}} P->foo(); // No warning. } @@ -135,7 +140,7 @@ { std::unique_ptr P; pass_smart_ptr_by_const_rvalue_ref(std::move(P)); - P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + P->foo(); // no-warning } { std::unique_ptr P; @@ -145,7 +150,7 @@ { std::unique_ptr P; pass_smart_ptr_by_const_ptr(&P); - P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} + P->foo(); // no-warning } } @@ -179,17 +184,17 @@ { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S)); - S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} + S.P->foo(); // no-warning } { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_ptr(&S); - S.P->foo(); + S.P->foo(); // no-warning } { StructWithSmartPtr S; pass_struct_with_smart_ptr_by_const_ptr(&S); - S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} + S.P->foo(); // no-warning } } @@ -217,14 +222,20 @@ (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } -void derefOnStdSwappedNullPtr() { +void derefOnFirstStdSwappedNullPtr() { std::unique_ptr P; std::unique_ptr PNull; std::swap(P, PNull); - PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} } +void derefOnSecondStdSwappedNullPtr() { + std::unique_ptr P; + std::unique_ptr PNull; + std::swap(P, PNull); + PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} +} + void derefOnSwappedValidPtr() { std::unique_ptr P(new A()); std::unique_ptr PValid(new A());