Index: include/string =================================================================== --- include/string +++ include/string @@ -825,7 +825,9 @@ basic_string& operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); #endif - _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const value_type* __s) {return assign(__s);} + _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const value_type* __s) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") + {return assign(__s);} basic_string& operator=(value_type __c); #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS _LIBCPP_INLINE_VISIBILITY @@ -1539,6 +1541,7 @@ inline _LIBCPP_INLINE_VISIBILITY basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s) { + // FIXME: Add _LIBCPP_DIAGNOSE_WARNING _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*) detected nullptr"); __init(__s, traits_type::length(__s)); #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1548,9 +1551,11 @@ template inline _LIBCPP_INLINE_VISIBILITY -basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, const allocator_type& __a) +basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, + const allocator_type& __a) : __r_(__a) { + // FIXME: Add _LIBCPP_DIAGNOSE_WARNING _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*, allocator) detected nullptr"); __init(__s, traits_type::length(__s)); #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1560,8 +1565,10 @@ template inline _LIBCPP_INLINE_VISIBILITY -basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n) +basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, + size_type __n) { + // FIXME: Add _LIBCPP_DIAGNOSE_WARNING _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr"); __init(__s, __n); #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1571,7 +1578,9 @@ template inline _LIBCPP_INLINE_VISIBILITY -basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n, const allocator_type& __a) +basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, + size_type __n, + const allocator_type& __a) : __r_(__a) { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr"); @@ -1733,7 +1742,7 @@ __init(__sv.data(), __sv.size()); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); -#endif +#endif } template @@ -1940,6 +1949,7 @@ template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr"); size_type __cap = capacity(); @@ -2127,6 +2137,7 @@ template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::assign received nullptr"); return assign(__s, traits_type::length(__s)); @@ -2137,6 +2148,7 @@ template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n) + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append received nullptr"); size_type __cap = capacity(); @@ -2243,7 +2255,7 @@ const basic_string __temp (__first, __last, __alloc()); append(__temp.data(), __temp.size()); } - else + else { if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); @@ -2294,6 +2306,7 @@ template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::append received nullptr"); return append(__s, traits_type::length(__s)); @@ -2303,7 +2316,10 @@ template basic_string<_CharT, _Traits, _Allocator>& -basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n) +basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, + const value_type* __s, + size_type __n) + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::insert received nullptr"); size_type __sz = size(); @@ -2471,6 +2487,7 @@ template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::insert received nullptr"); return insert(__pos, __s, traits_type::length(__s)); @@ -2521,7 +2538,11 @@ template basic_string<_CharT, _Traits, _Allocator>& -basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2) +basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, + size_type __n1, + const value_type* __s, + size_type __n2) + _LIBCPP_DIAGNOSE_WARNING(__n2 > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::replace received nullptr"); size_type __sz = size(); @@ -2656,7 +2677,10 @@ template basic_string<_CharT, _Traits, _Allocator>& -basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s) +basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, + size_type __n1, + const value_type* __s) + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::replace received nullptr"); return replace(__pos, __n1, __s, traits_type::length(__s)); @@ -3033,6 +3057,7 @@ basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find(): received nullptr"); return __str_find @@ -3064,6 +3089,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::find(): received nullptr"); return __str_find @@ -3086,6 +3112,7 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::rfind(): received nullptr"); return __str_rfind @@ -3117,6 +3144,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::rfind(): received nullptr"); return __str_rfind @@ -3139,6 +3167,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_of(): received nullptr"); return __str_find_first_of @@ -3170,6 +3199,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::find_first_of(): received nullptr"); return __str_find_first_of @@ -3192,6 +3222,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_of(): received nullptr"); return __str_find_last_of @@ -3223,6 +3254,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::find_last_of(): received nullptr"); return __str_find_last_of @@ -3245,6 +3277,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_not_of(): received nullptr"); return __str_find_first_not_of @@ -3276,6 +3309,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::find_first_not_of(): received nullptr"); return __str_find_first_not_of @@ -3299,6 +3333,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__n > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_not_of(): received nullptr"); return __str_find_last_not_of @@ -3330,6 +3365,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s, size_type __pos) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::find_last_not_of(): received nullptr"); return __str_find_last_not_of @@ -3380,6 +3416,7 @@ size_type __n1, const value_type* __s, size_type __n2) const + _LIBCPP_DIAGNOSE_WARNING(__n2 > 0 && __s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::compare(): received nullptr"); size_type __sz = size(); @@ -3448,6 +3485,7 @@ template int basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::compare(): received nullptr"); return compare(0, npos, __s, traits_type::length(__s)); @@ -3458,6 +3496,7 @@ basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1, size_type __n1, const value_type* __s) const + _LIBCPP_DIAGNOSE_WARNING(__s == nullptr, "pointer cannot be null") { _LIBCPP_ASSERT(__s != nullptr, "string::compare(): received nullptr"); return compare(__pos1, __n1, __s, traits_type::length(__s)); @@ -3519,6 +3558,7 @@ bool operator==(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { typedef basic_string<_CharT, _Traits, _Allocator> _String; _LIBCPP_ASSERT(__lhs != nullptr, "operator==(char*, basic_string): received nullptr"); @@ -3532,6 +3572,7 @@ bool operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { typedef basic_string<_CharT, _Traits, _Allocator> _String; _LIBCPP_ASSERT(__rhs != nullptr, "operator==(basic_string, char*): received nullptr"); @@ -3554,6 +3595,7 @@ bool operator!=(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { return !(__lhs == __rhs); } @@ -3563,6 +3605,7 @@ bool operator!=(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { return !(__lhs == __rhs); } @@ -3583,6 +3626,7 @@ bool operator< (const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { return __lhs.compare(__rhs) < 0; } @@ -3592,6 +3636,7 @@ bool operator< (const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { return __rhs.compare(__lhs) > 0; } @@ -3612,6 +3657,7 @@ bool operator> (const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { return __rhs < __lhs; } @@ -3621,6 +3667,7 @@ bool operator> (const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { return __rhs < __lhs; } @@ -3641,6 +3688,7 @@ bool operator<=(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { return !(__rhs < __lhs); } @@ -3650,6 +3698,7 @@ bool operator<=(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { return !(__rhs < __lhs); } @@ -3670,6 +3719,7 @@ bool operator>=(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__rhs == nullptr, "pointer cannot be null") { return !(__lhs < __rhs); } @@ -3679,6 +3729,7 @@ bool operator>=(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT + _LIBCPP_DIAGNOSE_WARNING(__lhs == nullptr, "pointer cannot be null") { return !(__lhs < __rhs); } Index: test/libcxx/strings/diagnose_null_pointer.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/strings/diagnose_null_pointer.fail.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 +// REQUIRES: diagnose-if-support, verify-support + +// Test that libc++ generates a warning diagnostic when the container is +// provided a non-const callable comparator. + +#include +#include + +void test_constructors() { +#if 0 // FIXME: Add diagnose_if to string constructors + std::string s1(nullptr); // expected-warning 1+ {{cannot construct string from a null pointer}} + std::string s2(nullptr, std::allocator()); // expected-warning 1+ {{cannot construct string from a null pointer}} + std::string s3(nullptr, 0); + std::string s4(nullptr, 1); // expected-warning 1+ {{cannot construct string from a null pointer}} + std::string s5(nullptr, 0, std::allocator()); + std::string s6(nullptr, 1, std::allocator()); // expected-warning 1+ {{cannot construct string from a null pointer}} +#endif +} + +void test_assignment() { + std::string s1; + s1 = nullptr; // expected-warning 1+ {{pointer cannot be null}} + s1.assign(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} + s1.assign(nullptr); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_append() { + std::string s; + s.append(nullptr, 0); + s.append(nullptr, 1); // expected-warning 1+ {{pointer cannot be null}} + s.append(nullptr); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_insert() { + std::string s; + s.insert(0, nullptr, 0); // OK + s.insert(0, nullptr, 1); // expected-warning 1+ {{pointer cannot be null}} + s.insert(0, nullptr); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_replace() { + std::string s; + s.replace(0, 0, nullptr, 0); + s.replace(0, 0, nullptr, 1); // expected-warning 1+ {{pointer cannot be null}} + s.replace(0, 0, nullptr); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_find() { + std::string s; + s.find(nullptr, 0, 0); + s.find(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.find(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_rfind() { + std::string s; + s.rfind(nullptr, 0, 0); + s.rfind(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.rfind(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_find_first_of() { + std::string s; + s.find_first_of(nullptr, 0, 0); + s.find_first_of(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.find_first_of(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_find_last_of() { + std::string s; + s.find_last_of(nullptr, 0, 0); + s.find_last_of(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.find_last_of(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + + +void test_find_first_not_of() { + std::string s; + s.find_first_not_of(nullptr, 0, 0); + s.find_first_not_of(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.find_first_not_of(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_find_last_not_of() { + std::string s; + s.find_last_not_of(nullptr, 0, 0); + s.find_last_not_of(nullptr, 0, 1); // expected-warning 1+ {{pointer cannot be null}} + s.find_last_not_of(nullptr, 0); // expected-warning 1+ {{pointer cannot be null}} +} + +void test_compare() { + std::string s; + s.compare(0, 0, nullptr, 0); + s.compare(0, 0, nullptr, 1); // expected-warning 1+ {{pointer cannot be null}} + s.compare(0, 0, nullptr); // expected-warning 1+ {{pointer cannot be null}} + s.compare(nullptr); // expected-warning 1+ {{pointer cannot be null}} +} + +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-comparison" +#endif + +void test_comparison_operators() { + std::string s; + s == static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) == s; // expected-warning 1+ {{pointer cannot be null}} + s != static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) != s; // expected-warning 1+ {{pointer cannot be null}} + s < static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) < s; // expected-warning 1+ {{pointer cannot be null}} + s <= static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) <= s; // expected-warning 1+ {{pointer cannot be null}} + s > static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) > s; // expected-warning 1+ {{pointer cannot be null}} + s >= static_cast(nullptr); // expected-warning 1+ {{pointer cannot be null}} + static_cast(nullptr) >= s; // expected-warning 1+ {{pointer cannot be null}} +} + +int main() { + test_constructors(); + test_assignment(); + test_append(); + test_insert(); + test_replace(); + test_find(); + test_rfind(); + test_find_first_of(); + test_find_last_of(); + test_find_first_not_of(); + test_find_last_not_of(); + test_compare(); + test_comparison_operators(); +}