Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -495,12 +495,15 @@ /// implementation, about which we know that it is inlined. /// FIXME: This could definitely be improved upon. static bool shouldEscapeRegion(const MemRegion *R) { + if (!R->hasStackStorage()) + return true; + if (isSmartPtrField(R)) return false; const auto *VR = dyn_cast(R); - if (!R->hasStackStorage() || !VR) + if (!VR) return true; const VarDecl *VD = VR->getDecl(); Index: clang/test/Analysis/os_smart_ptr.h =================================================================== --- clang/test/Analysis/os_smart_ptr.h +++ clang/test/Analysis/os_smart_ptr.h @@ -5,6 +5,8 @@ namespace os { +static struct no_retain_t {} no_retain; + template struct smart_ptr { smart_ptr() : pointer(nullptr) {} @@ -15,6 +17,8 @@ } } + explicit smart_ptr(T *&p, no_retain_t) : pointer(p) {} + smart_ptr(smart_ptr const &rhs) : pointer(rhs.pointer) { if (pointer) { _retain(pointer); @@ -31,6 +35,12 @@ return *this; } + smart_ptr & + operator=(smart_ptr const &rhs) { + smart_ptr(rhs.get()).swap(*this); + return *this; + } + ~smart_ptr() { if (pointer) { _release(pointer); Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -591,15 +591,15 @@ { OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr'}} // expected-note@-1{{Returning from constructor for 'smart_ptr'}} - // expected-note@os_smart_ptr.h:13{{Taking true branch}} - // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}} - // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}} - // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}} + // expected-note@os_smart_ptr.h:15{{Taking true branch}} + // expected-note@os_smart_ptr.h:16{{Calling 'smart_ptr::_retain'}} + // expected-note@os_smart_ptr.h:81{{Reference count incremented. The object now has a +2 retain count}} + // expected-note@os_smart_ptr.h:16{{Returning from 'smart_ptr::_retain'}} } // expected-note{{Calling '~smart_ptr'}} - // expected-note@os_smart_ptr.h:35{{Taking true branch}} - // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}} - // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}} - // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}} + // expected-note@os_smart_ptr.h:45{{Taking true branch}} + // expected-note@os_smart_ptr.h:46{{Calling 'smart_ptr::_release'}} + // expected-note@os_smart_ptr.h:86{{Reference count decremented. The object now has a +1 retain count}} + // expected-note@os_smart_ptr.h:46{{Returning from 'smart_ptr::_release'}} // expected-note@-5{{Returning from '~smart_ptr'}} obj->release(); // expected-note{{Object released}} obj->release(); // expected-warning{{Reference-counted object is used after it is released}} @@ -611,15 +611,15 @@ { OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr'}} // expected-note@-1{{Returning from constructor for 'smart_ptr'}} - // expected-note@os_smart_ptr.h:13{{Taking true branch}} - // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}} - // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}} - // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}} + // expected-note@os_smart_ptr.h:15{{Taking true branch}} + // expected-note@os_smart_ptr.h:16{{Calling 'smart_ptr::_retain'}} + // expected-note@os_smart_ptr.h:81{{Reference count incremented. The object now has a +2 retain count}} + // expected-note@os_smart_ptr.h:16{{Returning from 'smart_ptr::_retain'}} } // expected-note{{Calling '~smart_ptr'}} - // expected-note@os_smart_ptr.h:35{{Taking true branch}} - // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}} - // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}} - // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}} + // expected-note@os_smart_ptr.h:45{{Taking true branch}} + // expected-note@os_smart_ptr.h:46{{Calling 'smart_ptr::_release'}} + // expected-note@os_smart_ptr.h:86{{Reference count decremented. The object now has a +1 retain count}} + // expected-note@os_smart_ptr.h:46{{Returning from 'smart_ptr::_release'}} // expected-note@-5{{Returning from '~smart_ptr'}} } // expected-warning{{Potential leak of an object stored into 'obj'}} // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}} @@ -660,3 +660,13 @@ obj->release(); } +struct B { + OSObjectPtr p; + B(OSObjectPtr p) : p(p) {} + + B test_escape_smart_ptr_into_field() { + OSObject *obj = new OSObject; + return B(OSObjectPtr(obj, os::no_retain)); + } +}; +