From 3075014f2dd78f369e099e2b4e98629d89fc8ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 4 Sep 2014 00:15:56 +0200 Subject: [PATCH] Added check for types with no virtual destructor when using default_delete and non-array types --- include/boost/move/default_delete.hpp | 16 ++++- .../move/detail/unique_ptr_meta_utils.hpp | 69 ++++++++++++++++++- include/boost/move/unique_ptr.hpp | 29 +++++++- proj/vc7ide/Move.sln | 1 + 4 files changed, 109 insertions(+), 6 deletions(-) diff --git a/include/boost/move/default_delete.hpp b/include/boost/move/default_delete.hpp index dab8a83..d8ad360 100644 --- a/include/boost/move/default_delete.hpp +++ b/include/boost/move/default_delete.hpp @@ -128,7 +128,11 @@ struct default_delete default_delete(const default_delete& BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_def_del::type* =0) ) BOOST_NOEXCEPT - {} + { + //If T is not an array type, U derives from T + //and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor::value )); + } //! Effects: Constructs a default_delete object from another default_delete object. //! @@ -139,7 +143,12 @@ struct default_delete BOOST_MOVE_DOC1ST(default_delete&, typename bmupd::enable_def_del::type) operator=(const default_delete&) BOOST_NOEXCEPT - { return *this; } + { + //If T is not an array type, U derives from T + //and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor::value )); + return *this; + } //! Effects: if T is not an array type, calls delete on static_cast(ptr), //! otherwise calls delete[] on static_cast::type*>(ptr). @@ -155,6 +164,9 @@ struct default_delete { //U must be a complete type BOOST_STATIC_ASSERT(sizeof(U) > 0); + //If T is not an array type, U derives from T + //and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor::value )); element_type * const p = static_cast(ptr); bmupmu::is_array::value ? delete [] p : delete p; } diff --git a/include/boost/move/detail/unique_ptr_meta_utils.hpp b/include/boost/move/detail/unique_ptr_meta_utils.hpp index 33e4d52..89143a7 100644 --- a/include/boost/move/detail/unique_ptr_meta_utils.hpp +++ b/include/boost/move/detail/unique_ptr_meta_utils.hpp @@ -20,6 +20,13 @@ namespace boost { +namespace movelib { + +template +struct default_delete; + +} //namespace movelib { + #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES //Forward declare boost::rv template class rv; @@ -423,7 +430,7 @@ class is_convertible #endif ////////////////////////////////////// -// is_unary_function +// is_unary_function ////////////////////////////////////// #if defined(BOOST_MSVC) || defined(__BORLANDC_) #define BOOST_MOVE_TT_DECL __cdecl @@ -517,6 +524,66 @@ template struct is_unary_function { static const bool value = is_unary_function_impl::value; }; +////////////////////////////////////// +// has_virtual_destructor +////////////////////////////////////// +#if (defined(BOOST_MSVC) && defined(BOOST_MSVC_FULL_VER) && (BOOST_MSVC_FULL_VER >=140050215))\ + || (defined(BOOST_INTEL) && defined(_MSC_VER) && (_MSC_VER >= 1500)) +# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +#elif defined(BOOST_CLANG) && defined(__has_feature) +# if __has_feature(has_virtual_destructor) +# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +# endif +#elif defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3) && !defined(__GCCXML__))) && !defined(BOOST_CLANG) +# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +#elif defined(__ghs__) && (__GHS_VERSION_NUMBER >= 600) +# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +#elif defined(__CODEGEARC__) +# define BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T) __has_virtual_destructor(T) +#endif + +#ifdef BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR + template + struct has_virtual_destructor{ static const bool value = BOOST_MOVEUP_HAS_VIRTUAL_DESTRUCTOR(T); }; +#else + //If no intrinsic is available you trust the programmer knows what is doing + template + struct has_virtual_destructor{ static const bool value = true; }; +#endif + +////////////////////////////////////// +// missing_virtual_destructor +////////////////////////////////////// + +template< class T, class U + , bool enable = is_convertible< typename remove_cv::type* + , typename remove_cv::type*>::value && + !is_array::value && + !is_same::type, void>::value && + !is_same::type, typename remove_cv::type>::value + > +struct missing_virtual_destructor_default_delete +{ + static const bool value = !has_virtual_destructor::value; +}; + +template +struct missing_virtual_destructor_default_delete +{ + static const bool value = false; +}; + +template +struct missing_virtual_destructor +{ + static const bool value = false; +}; + +template +struct missing_virtual_destructor< ::boost::movelib::default_delete, U > + : missing_virtual_destructor_default_delete +{}; + } //namespace move_upmu { } //namespace boost { diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index a78ca66..be74a1f 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -411,6 +411,10 @@ class unique_ptr ) BOOST_NOEXCEPT : m_data(p) { + //If T is not an array type, element_type_t derives from T + //it uses the default deleter and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor + ::type>::value )); //If this constructor is instantiated with a pointer type or reference type //for the template argument D, the program is ill-formed. BOOST_STATIC_ASSERT(!bmupmu::is_pointer::value); @@ -444,7 +448,12 @@ class unique_ptr BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr::type* =0) ) BOOST_NOEXCEPT : m_data(p, d1) - {} + { + //If T is not an array type, element_type_t derives from T + //it uses the default deleter and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor + ::type>::value )); + } //! Effects: Same effects as template unique_ptr(Pointer p, deleter_arg_type1 d1) //! and additionally get() == nullptr @@ -477,7 +486,12 @@ class unique_ptr BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_ptr::type* =0) ) BOOST_NOEXCEPT : m_data(p, ::boost::move(d2)) - {} + { + //If T is not an array type, element_type_t derives from T + //it uses the default deleter and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor + ::type>::value )); + } //! Effects: Same effects as template unique_ptr(Pointer p, deleter_arg_type2 d2) //! and additionally get() == nullptr @@ -519,7 +533,12 @@ class unique_ptr BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_moveconv_constr::type* =0) ) BOOST_NOEXCEPT : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) - {} + { + //If T is not an array type, U derives from T + //it uses the default deleter and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor + ::pointer>::value )); + } //! Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, //! and shall not throw exceptions. @@ -673,6 +692,10 @@ class unique_ptr BOOST_MOVE_DOC1ST(void, typename bmupd::enable_up_ptr::type) reset(Pointer p) BOOST_NOEXCEPT { + //If T is not an array type, element_type_t derives from T + //it uses the default deleter and T has no virtual destructor, then you have a problem + BOOST_STATIC_ASSERT(( !::boost::move_upmu::missing_virtual_destructor + ::type>::value )); pointer tmp = m_data.m_p; m_data.m_p = p; if(tmp) m_data.deleter()(tmp); diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index b43ac07..c12681b 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -231,6 +231,7 @@ Global ..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp ..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp ..\..\..\..\boost\move\unique_ptr.hpp = ..\..\..\..\boost\move\unique_ptr.hpp + ..\..\..\..\boost\move\detail\unique_ptr_meta_utils.hpp = ..\..\..\..\boost\move\detail\unique_ptr_meta_utils.hpp ..\..\test\unique_ptr_test_utils_beg.hpp = ..\..\test\unique_ptr_test_utils_beg.hpp ..\..\test\unique_ptr_test_utils_end.hpp = ..\..\test\unique_ptr_test_utils_end.hpp ..\..\..\..\boost\move\utility.hpp = ..\..\..\..\boost\move\utility.hpp