546 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\2// RUN: -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\3// RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\4// RUN: -std=c++11 -verify %s5 6// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\7// RUN: -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\8// RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\9// RUN: -std=c++20 -verify %s10 11#include "Inputs/system-header-simulator-cxx.h"12 13void clang_analyzer_warnIfReached();14void clang_analyzer_numTimesReached();15void clang_analyzer_eval(bool);16void clang_analyzer_warnOnDeadSymbol(int *);17 18void derefAfterMove(std::unique_ptr<int> P) {19 std::unique_ptr<int> Q = std::move(P);20 if (Q)21 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}22 *Q.get() = 1; // expected-warning {{Dereference of null pointer [core.NullDereference]}}23 if (P)24 clang_analyzer_warnIfReached(); // no-warning25 // TODO: Report a null dereference (instead).26 *P.get() = 1; // expected-warning {{Method called on moved-from object 'P' [cplusplus.Move]}}27 // expected-warning@-1 {{Dereference of null pointer [core.NullDereference]}}28}29 30// Don't crash when attempting to model a call with unknown callee.31namespace testUnknownCallee {32struct S {33 void foo();34};35void bar(S *s, void (S::*func)(void)) {36 (s->*func)(); // no-crash37}38} // namespace testUnknownCallee39 40class A {41public:42 A(){};43 void foo();44};45 46A *return_null() {47 return nullptr;48}49 50void derefAfterValidCtr() {51 std::unique_ptr<A> P(new A());52 clang_analyzer_numTimesReached(); // expected-warning {{1}}53 P->foo(); // No warning.54}55 56void derefOfUnknown(std::unique_ptr<A> P) {57 P->foo(); // No warning.58}59 60void derefAfterDefaultCtr() {61 std::unique_ptr<A> P;62 clang_analyzer_numTimesReached(); // expected-warning {{1}}63 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}64}65 66void derefAfterCtrWithNull() {67 std::unique_ptr<A> P(nullptr);68 clang_analyzer_numTimesReached(); // expected-warning {{1}}69 *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}70}71 72void derefAfterCtrWithNullVariable() {73 A *InnerPtr = nullptr;74 std::unique_ptr<A> P(InnerPtr);75 clang_analyzer_numTimesReached(); // expected-warning {{1}}76 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}77}78 79void derefAfterRelease() {80 std::unique_ptr<A> P(new A());81 P.release();82 clang_analyzer_numTimesReached(); // expected-warning {{1}}83 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}84}85 86void derefAfterReset() {87 std::unique_ptr<A> P(new A());88 P.reset();89 clang_analyzer_numTimesReached(); // expected-warning {{1}}90 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}91}92 93void derefAfterResetWithNull() {94 std::unique_ptr<A> P(new A());95 P.reset(nullptr);96 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}97}98 99void derefAfterResetWithNonNull() {100 std::unique_ptr<A> P;101 P.reset(new A());102 clang_analyzer_numTimesReached(); // expected-warning {{1}}103 P->foo(); // No warning.104}105 106void derefAfterReleaseAndResetWithNonNull() {107 std::unique_ptr<A> P(new A());108 P.release();109 P.reset(new A());110 P->foo(); // No warning.111}112 113void derefOnReleasedNullRawPtr() {114 std::unique_ptr<A> P;115 A *AP = P.release();116 AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}117}118 119void derefOnReleasedValidRawPtr() {120 std::unique_ptr<A> P(new A());121 A *AP = P.release();122 AP->foo(); // No warning.123}124 125void pass_smart_ptr_by_ref(std::unique_ptr<A> &a);126void pass_smart_ptr_by_const_ref(const std::unique_ptr<A> &a);127void pass_smart_ptr_by_rvalue_ref(std::unique_ptr<A> &&a);128void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr<A> &&a);129void pass_smart_ptr_by_ptr(std::unique_ptr<A> *a);130void pass_smart_ptr_by_const_ptr(const std::unique_ptr<A> *a);131 132void regioninvalidationWithPassByRef() {133 std::unique_ptr<A> P;134 pass_smart_ptr_by_ref(P);135 P->foo(); // no-warning136}137 138void regioninvalidationWithPassByCostRef() {139 std::unique_ptr<A> P;140 pass_smart_ptr_by_const_ref(P);141 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}142}143 144void regioninvalidationWithPassByRValueRef() {145 std::unique_ptr<A> P;146 pass_smart_ptr_by_rvalue_ref(std::move(P));147 P->foo(); // no-warning148}149 150void regioninvalidationWithPassByConstRValueRef() {151 std::unique_ptr<A> P;152 pass_smart_ptr_by_const_rvalue_ref(std::move(P));153 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}154}155 156void regioninvalidationWithPassByPtr() {157 std::unique_ptr<A> P;158 pass_smart_ptr_by_ptr(&P);159 P->foo();160}161 162void regioninvalidationWithPassByConstPtr() {163 std::unique_ptr<A> P;164 pass_smart_ptr_by_const_ptr(&P);165 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}166}167 168struct StructWithSmartPtr {169 std::unique_ptr<A> P;170};171 172void pass_struct_with_smart_ptr_by_ref(StructWithSmartPtr &a);173void pass_struct_with_smart_ptr_by_const_ref(const StructWithSmartPtr &a);174void pass_struct_with_smart_ptr_by_rvalue_ref(StructWithSmartPtr &&a);175void pass_struct_with_smart_ptr_by_const_rvalue_ref(const StructWithSmartPtr &&a);176void pass_struct_with_smart_ptr_by_ptr(StructWithSmartPtr *a);177void pass_struct_with_smart_ptr_by_const_ptr(const StructWithSmartPtr *a);178 179void regioninvalidationWithinStructPassByRef() {180 StructWithSmartPtr S;181 pass_struct_with_smart_ptr_by_ref(S);182 S.P->foo(); // no-warning183}184 185void regioninvalidationWithinStructPassByConstRef() {186 StructWithSmartPtr S;187 pass_struct_with_smart_ptr_by_const_ref(S);188 S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}189}190 191void regioninvalidationWithinStructPassByRValueRef() {192 StructWithSmartPtr S;193 pass_struct_with_smart_ptr_by_rvalue_ref(std::move(S));194 S.P->foo(); // no-warning195}196 197void regioninvalidationWithinStructPassByConstRValueRef() {198 StructWithSmartPtr S;199 pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S));200 S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}201}202 203void regioninvalidationWithinStructPassByPtr() {204 StructWithSmartPtr S;205 pass_struct_with_smart_ptr_by_ptr(&S);206 S.P->foo(); // no-warning207}208 209void regioninvalidationWithinStructPassByConstPtr() {210 StructWithSmartPtr S;211 pass_struct_with_smart_ptr_by_const_ptr(&S);212 S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}213}214 215void derefAfterAssignment() {216 {217 std::unique_ptr<A> P(new A());218 std::unique_ptr<A> Q;219 Q = std::move(P);220 Q->foo(); // no-warning221 }222 {223 std::unique_ptr<A> P;224 std::unique_ptr<A> Q;225 Q = std::move(P);226 Q->foo(); // expected-warning {{Dereference of null smart pointer 'Q' [alpha.cplusplus.SmartPtr]}}227 }228}229 230void derefOnSwappedNullPtr() {231 std::unique_ptr<A> P(new A());232 std::unique_ptr<A> PNull;233 P.swap(PNull);234 PNull->foo(); // No warning.235 (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}236}237 238void derefOnFirstStdSwappedNullPtr() {239 std::unique_ptr<A> P;240 std::unique_ptr<A> PNull;241 std::swap(P, PNull);242 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}243}244 245void derefOnSecondStdSwappedNullPtr() {246 std::unique_ptr<A> P;247 std::unique_ptr<A> PNull;248 std::swap(P, PNull);249 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}250}251 252void derefOnSwappedValidPtr() {253 std::unique_ptr<A> P(new A());254 std::unique_ptr<A> PValid(new A());255 P.swap(PValid);256 (*P).foo(); // No warning.257 PValid->foo(); // No warning.258 std::swap(P, PValid);259 P->foo(); // No warning.260 PValid->foo(); // No warning.261}262 263void derefOnRawPtrFromGetOnNullPtr() {264 std::unique_ptr<A> P;265 P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}266}267 268void derefOnRawPtrFromGetOnValidPtr() {269 std::unique_ptr<A> P(new A());270 P.get()->foo(); // No warning.271}272 273void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P) {274 P.get()->foo(); // No warning.275}276 277void derefOnRawPtrFromMultipleGetOnUnknownPtr(std::unique_ptr<A> P) {278 A *X = P.get();279 A *Y = P.get();280 clang_analyzer_eval(X == Y); // expected-warning{{TRUE}}281 if (!X) {282 Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}283 }284}285 286void derefOnMovedFromValidPtr() {287 std::unique_ptr<A> PToMove(new A());288 std::unique_ptr<A> P;289 P = std::move(PToMove);290 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}291}292 293void derefOnMovedToNullPtr() {294 std::unique_ptr<A> PToMove(new A());295 std::unique_ptr<A> P;296 P = std::move(PToMove); // No note.297 P->foo(); // No warning.298}299 300void derefOnNullPtrGotMovedFromValidPtr() {301 std::unique_ptr<A> P(new A());302 std::unique_ptr<A> PToMove;303 P = std::move(PToMove);304 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}305}306 307void derefOnMovedFromUnknownPtr(std::unique_ptr<A> PToMove) {308 std::unique_ptr<A> P;309 P = std::move(PToMove);310 P->foo(); // No warning.311}312 313void derefOnMovedUnknownPtr(std::unique_ptr<A> PToMove) {314 std::unique_ptr<A> P;315 P = std::move(PToMove);316 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}317}318 319void derefOnAssignedNullPtrToNullSmartPtr() {320 std::unique_ptr<A> P;321 P = nullptr;322 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}323}324 325void derefOnAssignedZeroToNullSmartPtr() {326 std::unique_ptr<A> P(new A());327 P = 0;328 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}329}330 331void derefOnAssignedNullToUnknowSmartPtr(std::unique_ptr<A> P) {332 P = nullptr;333 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}334}335 336std::unique_ptr<A> &&returnRValRefOfUniquePtr();337 338void drefOnAssignedNullFromMethodPtrValidSmartPtr() {339 std::unique_ptr<A> P(new A());340 P = returnRValRefOfUniquePtr();341 P->foo(); // No warning.342}343 344void derefMoveConstructedWithValidPtr() {345 std::unique_ptr<A> PToMove(new A());346 std::unique_ptr<A> P(std::move(PToMove));347 P->foo(); // No warning.348}349 350void derefMoveConstructedWithNullPtr() {351 std::unique_ptr<A> PToMove;352 std::unique_ptr<A> P(std::move(PToMove));353 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}354}355 356void derefMoveConstructedWithUnknownPtr(std::unique_ptr<A> PToMove) {357 std::unique_ptr<A> P(std::move(PToMove));358 P->foo(); // No warning.359}360 361void derefValidPtrMovedToConstruct() {362 std::unique_ptr<A> PToMove(new A());363 std::unique_ptr<A> P(std::move(PToMove));364 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}365}366 367void derefNullPtrMovedToConstruct() {368 std::unique_ptr<A> PToMove;369 std::unique_ptr<A> P(std::move(PToMove));370 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}371}372 373void derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove) {374 std::unique_ptr<A> P(std::move(PToMove));375 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}376}377 378std::unique_ptr<A> &&functionReturnsRValueRef();379 380void derefMoveConstructedWithRValueRefReturn() {381 std::unique_ptr<A> P(functionReturnsRValueRef());382 P->foo(); // No warning.383}384 385void derefConditionOnNullPtr() {386 std::unique_ptr<A> P;387 if (P)388 P->foo(); // No warning.389 else390 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}391}392 393void derefConditionOnNotNullPtr() {394 std::unique_ptr<A> P;395 if (!P)396 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}397}398 399void derefConditionOnValidPtr() {400 std::unique_ptr<A> P(new A());401 std::unique_ptr<A> PNull;402 if (P)403 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}404}405 406void derefConditionOnNotValidPtr() {407 std::unique_ptr<A> P(new A());408 std::unique_ptr<A> PNull;409 if (!P)410 PNull->foo(); // No warning.411}412 413void derefConditionOnUnKnownPtr(std::unique_ptr<A> P) {414 if (P)415 P->foo(); // No warning.416 else417 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}418}419 420void derefOnValidPtrAfterReset(std::unique_ptr<A> P) {421 P.reset(new A());422 if (!P)423 P->foo(); // No warning.424 else425 P->foo(); // No warning.426}427 428void innerPointerSymbolLiveness() {429 std::unique_ptr<int> P(new int());430 clang_analyzer_warnOnDeadSymbol(P.get());431 int *RP = P.release();432} // expected-warning{{SYMBOL DEAD}}433 434void boolOpCreatedConjuredSymbolLiveness(std::unique_ptr<int> P) {435 if (P) {436 int *X = P.get();437 clang_analyzer_warnOnDeadSymbol(X);438 }439} // expected-warning{{SYMBOL DEAD}}440 441void getCreatedConjuredSymbolLiveness(std::unique_ptr<int> P) {442 int *X = P.get();443 clang_analyzer_warnOnDeadSymbol(X);444 int Y;445 if (!P) {446 Y = *P.get(); // expected-warning {{Dereference of null pointer [core.NullDereference]}}447 // expected-warning@-1 {{SYMBOL DEAD}}448 }449}450 451int derefConditionOnUnKnownPtr(int *q) {452 std::unique_ptr<int> P(q);453 if (P)454 return *P; // No warning.455 else456 return *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}457}458 459void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr<A> P) {460 A *RP = P.get();461 if (!RP) {462 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}463 }464}465 466// The following is a silly function,467// but serves to test if we are picking out468// standard comparision functions from custom ones.469template <typename T>470bool operator<(std::unique_ptr<T> &x, double d);471 472void uniquePtrComparision(std::unique_ptr<int> unknownPtr) {473 auto ptr = std::unique_ptr<int>(new int(13));474 auto nullPtr = std::unique_ptr<int>();475 auto otherPtr = std::unique_ptr<int>(new int(29));476 477 clang_analyzer_eval(ptr == ptr); // expected-warning{{TRUE}}478 clang_analyzer_eval(ptr > ptr); // expected-warning{{FALSE}}479 clang_analyzer_eval(ptr <= ptr); // expected-warning{{TRUE}}480 481 clang_analyzer_eval(nullPtr <= unknownPtr); // expected-warning{{TRUE}}482 clang_analyzer_eval(unknownPtr >= nullPtr); // expected-warning{{TRUE}}483 484 clang_analyzer_eval(ptr != otherPtr); // expected-warning{{TRUE}}485 clang_analyzer_eval(ptr > nullPtr); // expected-warning{{TRUE}}486 487 clang_analyzer_eval(ptr != nullptr); // expected-warning{{TRUE}}488 clang_analyzer_eval(nullPtr != nullptr); // expected-warning{{FALSE}}489 clang_analyzer_eval(nullptr <= unknownPtr); // expected-warning{{TRUE}}490}491 492void uniquePtrComparisionStateSplitting(std::unique_ptr<int> unknownPtr) {493 auto ptr = std::unique_ptr<int>(new int(13));494 495 clang_analyzer_eval(ptr > unknownPtr); // expected-warning{{TRUE}}496 // expected-warning@-1{{FALSE}}497}498 499void uniquePtrComparisionDifferingTypes(std::unique_ptr<int> unknownPtr) {500 auto ptr = std::unique_ptr<int>(new int(13));501 auto nullPtr = std::unique_ptr<A>();502 auto otherPtr = std::unique_ptr<double>(new double(3.14));503 504 clang_analyzer_eval(nullPtr <= unknownPtr); // expected-warning{{TRUE}}505 clang_analyzer_eval(unknownPtr >= nullPtr); // expected-warning{{TRUE}}506 507 clang_analyzer_eval(ptr != otherPtr); // expected-warning{{TRUE}}508 clang_analyzer_eval(ptr > nullPtr); // expected-warning{{TRUE}}509 510 clang_analyzer_eval(ptr != nullptr); // expected-warning{{TRUE}}511 clang_analyzer_eval(nullPtr != nullptr); // expected-warning{{FALSE}}512 clang_analyzer_eval(nullptr <= unknownPtr); // expected-warning{{TRUE}}513}514 515#if __cplusplus >= 202002L516 517void testOstreamOverload(std::unique_ptr<int> P) {518 auto &Cout = std::cout;519 auto &PtrCout = std::cout << P;520 auto &StringCout = std::cout << "hello";521 // We are testing the fact that in our modelling of522 // operator<<(basic_ostream<T1> &, const unique_ptr<T2> &)523 // we set the return SVal to the SVal of the ostream arg.524 clang_analyzer_eval(&Cout == &PtrCout); // expected-warning {{TRUE}}525 // FIXME: Technically, they should be equal,526 // that hasn't been modelled yet.527 clang_analyzer_eval(&Cout == &StringCout); // expected-warning {{UNKNOWN}}528}529 530int glob;531void testOstreamDoesntInvalidateGlobals(std::unique_ptr<int> P) {532 int x = glob;533 std::cout << P;534 int y = glob;535 clang_analyzer_eval(x == y); // expected-warning {{TRUE}}536}537 538#endif539 540// The following test isn't really a "smart-ptr" test541// It came up during a bug fix (D106296)542void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {543 // This should NOT crash.544 bar(true, false);545}546