| // RUN: %clang_analyze_cc1\ | |
| // RUN: -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\ | |
| // RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\ | |
| // RUN: -analyzer-output=text -std=c++20 %s -verify=expected | |
| // RUN: %clang_analyze_cc1\ | |
| // RUN: -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\ | |
| // RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\ | |
| // RUN: -analyzer-output=text -std=c++11 %s -verify=expected | |
| #include "Inputs/system-header-simulator-cxx.h" | |
| void clang_analyzer_eval(bool); | |
| class A { | |
| public: | |
| A(){}; | |
| void foo(); | |
| }; | |
| A *return_null() { | |
| return nullptr; | |
| } | |
| void derefAfterDefaultCtr() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefAfterCtrWithNull() { | |
| A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} | |
| std::unique_ptr<A> P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed using a null value}} | |
| *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefAfterCtrWithNullVariable() { | |
| A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} | |
| std::unique_ptr<A> P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed 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'}} | |
| } | |
| void derefAfterRelease() { | |
| std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}} | |
| // FIXME: should mark region as uninteresting after release, so above note will not be there | |
| 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<A> 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'}} | |
| } | |
| void derefAfterResetWithNull() { | |
| A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}} | |
| std::unique_ptr<A> 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'}} | |
| } | |
| // FIXME: Fix this test when support is added for tracking raw pointer | |
| // and mark the smart pointer as interesting based on that and add tags. | |
| void derefOnReleasedNullRawPtr() { | |
| std::unique_ptr<A> P; // FIXME: add note "Default constructed smart pointer 'P' is null" | |
| A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer value}} | |
| AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} | |
| // expected-note@-1{{Called C++ object pointer is null}} | |
| } | |
| void derefOnSwappedNullPtr() { | |
| std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}} | |
| std::unique_ptr<A> PNull; | |
| P.swap(PNull); | |
| PNull->foo(); // No warning. | |
| (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefOnStdSwappedNullPtr() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| std::unique_ptr<A> PNull; | |
| std::swap(P, PNull); | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| struct StructWithSmartPtr { // expected-note {{Default constructed smart pointer 'S.P' is null}} | |
| std::unique_ptr<A> P; | |
| }; | |
| void derefAfterDefaultCtrInsideStruct() { | |
| StructWithSmartPtr S; // expected-note {{Calling implicit default constructor for 'StructWithSmartPtr'}} | |
| // expected-note@-1 {{Returning from default constructor for 'StructWithSmartPtr'}} | |
| S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'S.P'}} | |
| } | |
| void noNoteTagsForNonInterestingRegion() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| std::unique_ptr<A> P1; // No note. | |
| std::unique_ptr<A> P2; // No note. | |
| P1.release(); // No note. | |
| P1.reset(); // No note. | |
| P1.swap(P2); // No note. | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefOnRawPtrFromGetOnNullPtr() { | |
| std::unique_ptr<A> P; // FIXME: add note "Default constructed smart pointer 'P' is null" | |
| P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} | |
| // expected-note@-1 {{Called C++ object pointer is null}} | |
| } | |
| void derefOnRawPtrFromGetOnValidPtr() { | |
| std::unique_ptr<A> P(new A()); | |
| P.get()->foo(); // No warning. | |
| } | |
| void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P) { | |
| P.get()->foo(); // No warning. | |
| } | |
| void derefOnMovedFromValidPtr() { | |
| std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}} | |
| // FIXME: above note should go away once we fix marking region not interested. | |
| std::unique_ptr<A> P; | |
| P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}} | |
| PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}} | |
| } | |
| void derefOnMovedToNullPtr() { | |
| std::unique_ptr<A> PToMove(new A()); | |
| std::unique_ptr<A> P; | |
| P = std::move(PToMove); // No note. | |
| P->foo(); // No warning. | |
| } | |
| void derefOnNullPtrGotMovedFromValidPtr() { | |
| std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}} | |
| // FIXME: above note should go away once we fix marking region not interested. | |
| std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}} | |
| P = std::move(PToMove); // expected-note {{A null pointer value is moved to 'P'}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1 {{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefOnMovedUnknownPtr(std::unique_ptr<A> PToMove) { | |
| std::unique_ptr<A> P; | |
| P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}} | |
| PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}} | |
| } | |
| void derefOnAssignedNullPtrToNullSmartPtr() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| P = nullptr; // expected-note {{Smart pointer 'P' is assigned 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 derefOnAssignedZeroToNullSmartPtr() { | |
| std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}} | |
| // FIXME: above note should go away once we fix marking region not interested. | |
| P = 0; // expected-note {{Smart pointer 'P' is assigned 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 derefMoveConstructedWithNullPtr() { | |
| std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}} | |
| std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| void derefValidPtrMovedToConstruct() { | |
| std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}} | |
| // FIXME: above note should go away once we fix marking region not interested. | |
| std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}} | |
| PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PToMove'}} | |
| } | |
| void derefNullPtrMovedToConstruct() { | |
| std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}} | |
| // FIXME: above note should go away once we fix marking region not interested. | |
| std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}} | |
| PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PToMove'}} | |
| } | |
| void derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove) { | |
| std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}} | |
| PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PToMove'}} | |
| } | |
| void derefConditionOnNullPtrFalseBranch() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| if (P) { // expected-note {{Taking false branch}} | |
| P->foo(); // No warning. | |
| } else { | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| } | |
| void derefConditionOnNullPtrTrueBranch() { | |
| std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}} | |
| if (!P) { // expected-note {{Taking true branch}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| } | |
| void derefConditionOnValidPtrTrueBranch() { | |
| std::unique_ptr<A> P(new A()); | |
| std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} | |
| if (P) { // expected-note {{Taking true branch}} | |
| PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PNull'}} | |
| } else { | |
| PNull->foo(); // No warning | |
| } | |
| } | |
| void derefConditionOnValidPtrFalseBranch() { | |
| std::unique_ptr<A> P(new A()); | |
| std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} | |
| if (!P) { // expected-note {{Taking false branch}} | |
| PNull->foo(); // No warning | |
| } else { | |
| PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PNull'}} | |
| } | |
| } | |
| void derefConditionOnNotValidPtr() { | |
| std::unique_ptr<A> P(new A()); | |
| std::unique_ptr<A> PNull; | |
| if (!P) | |
| PNull->foo(); // No warning. | |
| } | |
| void derefConditionOnUnKnownPtrAssumeNull(std::unique_ptr<A> P) { | |
| std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} | |
| if (!P) { // expected-note {{Taking true branch}} | |
| // expected-note@-1{{Assuming smart pointer 'P' is null}} | |
| PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PNull'}} | |
| } | |
| } | |
| void derefConditionOnUnKnownPtrAssumeNonNull(std::unique_ptr<A> P) { | |
| std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} | |
| if (P) { // expected-note {{Taking true branch}} | |
| // expected-note@-1{{Assuming smart pointer 'P' is non-null}} | |
| PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'PNull'}} | |
| } | |
| } | |
| void derefOnValidPtrAfterReset(std::unique_ptr<A> P) { | |
| P.reset(new A()); | |
| if (!P) | |
| P->foo(); // No warning. | |
| else | |
| P->foo(); // No warning. | |
| } | |
| struct S { | |
| std::unique_ptr<int> P; | |
| void foo() { | |
| if (!P) { // No-note because foo() is pruned | |
| return; | |
| } | |
| } | |
| int callingFooWithNullPointer() { | |
| foo(); // No note on Calling 'S::foo' | |
| P.reset(new int(0)); // expected-note {{Assigning 0}} | |
| return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}} | |
| // expected-note@-1 {{Division by zero}} | |
| } | |
| int callingFooWithValidPointer() { | |
| P.reset(new int(0)); // expected-note {{Assigning 0}} | |
| foo(); // No note on Calling 'S::foo' | |
| return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}} | |
| // expected-note@-1 {{Division by zero}} | |
| } | |
| int callingFooWithUnknownPointer(std::unique_ptr<int> PUnknown) { | |
| P.swap(PUnknown); | |
| foo(); // No note on Calling 'S::foo' | |
| P.reset(new int(0)); // expected-note {{Assigning 0}} | |
| return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}} | |
| // expected-note@-1 {{Division by zero}} | |
| } | |
| }; | |
| void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr<A> P) { | |
| A *RP = P.get(); | |
| if (!RP) { // expected-note {{Assuming 'RP' is null}} | |
| // expected-note@-1 {{Taking true branch}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| } | |
| void makeUniqueReturnsNonNullUniquePtr() { | |
| auto P = std::make_unique<A>(); | |
| if (!P) { // expected-note {{Taking false branch}} | |
| P->foo(); // should have no warning here, path is impossible | |
| } | |
| P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}} | |
| // Now P is null | |
| if (!P) { | |
| // expected-note@-1 {{Taking true branch}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| } | |
| #if __cplusplus >= 202002L | |
| void makeUniqueForOverwriteReturnsNullUniquePtr() { | |
| auto P = std::make_unique_for_overwrite<A>(); | |
| if (!P) { // expected-note {{Taking false branch}} | |
| P->foo(); // should have no warning here, path is impossible | |
| } | |
| P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}} | |
| // Now P is null | |
| if (!P) { | |
| // expected-note@-1 {{Taking true branch}} | |
| P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}} | |
| // expected-note@-1{{Dereference of null smart pointer 'P'}} | |
| } | |
| } | |
| #endif | |
| struct G { | |
| int *p; | |
| G(int *p): p(p) {} | |
| ~G() { *p = 0; } | |
| }; | |
| void foo() { | |
| int x = 1; | |
| { | |
| auto P = std::make_unique<G>(&x); | |
| // FIXME: There should not be a state split here, it should take the true path. | |
| clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}} | |
| // expected-warning@-1 {{FALSE}} | |
| // expected-note@-2 {{Assuming the condition is true}} | |
| // expected-note@-3 {{Assuming the condition is false}} | |
| // expected-note@-4 {{TRUE}} | |
| // expected-note@-5 {{FALSE}} | |
| // expected-note@-6 {{Assuming the condition is false}} | |
| } | |
| // FIXME: Should be fixed when unique_ptr desctructors are | |
| // properly modelled. This includes modelling the call to | |
| // the destructor of the inner pointer type. | |
| clang_analyzer_eval(x == 0); // expected-warning {{FALSE}} | |
| // expected-note@-1 {{FALSE}} | |
| } |