Author: marshall Date: Mon Jan 30 21:40:52 2017 New Revision: 293599 URL: http://llvm.org/viewvc/llvm-project?rev=293599&view=rev Log: Fix PR#31779: basic_string::operator= isn't exception safe.
Modified: libcxx/trunk/include/string libcxx/trunk/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp Modified: libcxx/trunk/include/string URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/string?rev=293599&r1=293598&r2=293599&view=diff ============================================================================== --- libcxx/trunk/include/string (original) +++ libcxx/trunk/include/string Mon Jan 30 21:40:52 2017 @@ -1367,12 +1367,28 @@ private: _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const basic_string& __str, true_type) { - if (__alloc() != __str.__alloc()) + if (__alloc() == __str.__alloc()) + __alloc() = __str.__alloc(); + else { - clear(); - shrink_to_fit(); + if (!__str.__is_long()) + { + clear(); + shrink_to_fit(); + __alloc() = __str.__alloc(); + } + else + { + allocator_type __a = __str.__alloc(); + pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap()); + clear(); + shrink_to_fit(); + __alloc() = _VSTD::move(__a); + __set_long_pointer(__p); + __set_long_cap(__str.__get_long_cap()); + __set_long_size(__str.size()); + } } - __alloc() = __str.__alloc(); } _LIBCPP_INLINE_VISIBILITY Modified: libcxx/trunk/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp?rev=293599&r1=293598&r2=293599&view=diff ============================================================================== --- libcxx/trunk/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp (original) +++ libcxx/trunk/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp Mon Jan 30 21:40:52 2017 @@ -18,6 +18,55 @@ #include "test_allocator.h" #include "min_allocator.h" +template <class T> +struct alloc_imp { + bool active; + + alloc_imp() : active(true) {} + + T* allocate(std::size_t n) + { + if (active) + return static_cast<T*>(std::malloc(n * sizeof(T))); + else + throw std::bad_alloc(); + } + + void deallocate(T* p, std::size_t) { std::free(p); } + void activate () { active = true; } + void deactivate() { active = false; } +}; + +template <class T> +struct poca_alloc { + typedef T value_type; + typedef std::true_type propagate_on_container_copy_assignment; + + alloc_imp<T> *imp; + + poca_alloc(alloc_imp<T> *imp) : imp (imp) {} + + template <class U> + poca_alloc(const poca_alloc<U>& other) : imp(other.imp) {} + + T* allocate (std::size_t n) { return imp->allocate(n);} + void deallocate(T* p, std::size_t n) { imp->deallocate(p, n); } +}; + +template <typename T, typename U> +bool operator==(const poca_alloc<T>& lhs, const poca_alloc<U>& rhs) +{ + return lhs.imp == rhs.imp; +} + +template <typename T, typename U> +bool operator!=(const poca_alloc<T>& lhs, const poca_alloc<U>& rhs) +{ + return lhs.imp != rhs.imp; +} + + + template <class S> void test(S s1, const typename S::allocator_type& a) @@ -29,6 +78,16 @@ test(S s1, const typename S::allocator_t assert(s2.get_allocator() == a); } +#ifndef TEST_HAS_NO_EXCEPTIONS +template <class S> +void test_assign(S &s1, const S& s2) +{ + try { s1 = s2; } + catch ( std::bad_alloc &) { return; } + assert(false); +} +#endif + int main() { { @@ -46,5 +105,27 @@ int main() test(S("1"), A()); test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A()); } + +#ifndef TEST_HAS_NO_EXCEPTIONS + { + typedef poca_alloc<char> A; + typedef std::basic_string<char, std::char_traits<char>, A> S; + const char * p1 = "This is my first string"; + const char * p2 = "This is my second string"; + + alloc_imp<char> imp1; + alloc_imp<char> imp2; + S s1(p1, A(&imp1)); + S s2(p2, A(&imp2)); + + assert(s1 == p1); + assert(s2 == p2); + + imp2.deactivate(); + test_assign(s1, s2); + assert(s1 == p1); + assert(s2 == p2); + } +#endif #endif } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits