EricWF created this revision. EricWF added reviewers: mclow.lists, danalbert, rsmith. EricWF added subscribers: cfe-commits, awi, rsmith.
This patch partially fixes the undefined behavior in `<list>`. The undefined behavior is caused by casting a pointer to `__node_base __end_` to the derived type `__node` even though `__end_` is not a sub-object of type `__node`. See C++14 [expr.static.cast]p11 > A prvalue of type “pointer to cv1 B,” where B is a class type, can be > converted to a prvalue of type “pointer to cv2 D,” where D is a class derived > (Clause 10) from B, if a valid standard conversion from “pointer to D” to > “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater > cv-qualification than, cv1, and B is neither a virtual base class of D nor a > base class of a virtual base class of D. The null pointer value (4.10) is > converted to the null pointer value of the destination type. If the prvalue > of type “pointer to cv1 B” points to a B that is actually a subobject of an > object of type D, the resulting pointer points to the enclosing object of > type D. Otherwise, the behavior is undefined. This patch fixes the problem by adding an intermediary void cast so that the conversion acts as if it were a reinterpret_cast. A reinterpret cast between pointer types is not used because this will not work with fancy pointers. This depends on the wording in: C++14 [expr.reinterpret.cast]p7 > An object pointer can be explicitly converted to an object pointer of a > different type. When a prvalue v of object pointer type is converted to the > object pointer type “pointer to cv T”, the result is static_cast<cv > T*>(static_cast<cv void*>(v)). Converting a prvalue of type “pointer to T1” > to the type “pointer to T2” (where T1 and T2 are object types and where the > alignment requirements of T2 are no stricter than those of T1) and back to > its original type yields the original pointer value. However, as @rsmith pointed out, this still has undefined behavior when the `element_type` stored in the list has a higher alignment requirement than that of a pointer. I will post a patch that completely fixes this problem but that likely involves an ABI break. http://reviews.llvm.org/D12297 Files: include/list Index: include/list =================================================================== --- include/list +++ include/list @@ -205,7 +205,8 @@ _LIBCPP_INLINE_VISIBILITY pointer __self() { - return static_cast<pointer>(pointer_traits<__base_pointer>::pointer_to(*this)); + return static_cast<pointer>(static_cast<_VoidPtr>( + pointer_traits<__base_pointer>::pointer_to(*this))); } }; @@ -543,22 +544,18 @@ iterator end() _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 - return iterator(static_cast<__node_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(__end_)), this); + return iterator(__end_.__self(), this); #else - return iterator(static_cast<__node_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(__end_))); + return iterator(__end_.__self()); #endif } _LIBCPP_INLINE_VISIBILITY const_iterator end() const _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 - return const_iterator(static_cast<__node_const_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_))), this); + return const_iterator(const_cast<__node_base&>(__end_).__self(), this); #else - return const_iterator(static_cast<__node_const_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_)))); + return const_iterator(const_cast<__node_base&>(__end_).__self()); #endif }
Index: include/list =================================================================== --- include/list +++ include/list @@ -205,7 +205,8 @@ _LIBCPP_INLINE_VISIBILITY pointer __self() { - return static_cast<pointer>(pointer_traits<__base_pointer>::pointer_to(*this)); + return static_cast<pointer>(static_cast<_VoidPtr>( + pointer_traits<__base_pointer>::pointer_to(*this))); } }; @@ -543,22 +544,18 @@ iterator end() _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 - return iterator(static_cast<__node_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(__end_)), this); + return iterator(__end_.__self(), this); #else - return iterator(static_cast<__node_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(__end_))); + return iterator(__end_.__self()); #endif } _LIBCPP_INLINE_VISIBILITY const_iterator end() const _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 - return const_iterator(static_cast<__node_const_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_))), this); + return const_iterator(const_cast<__node_base&>(__end_).__self(), this); #else - return const_iterator(static_cast<__node_const_pointer>( - pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_)))); + return const_iterator(const_cast<__node_base&>(__end_).__self()); #endif }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits