Skip to content

Commit 6080007

Browse files
[libc++] Fix strict aliasing violation for deque::const_iterator
When the allocators use fancy pointers, the internal map of `deque` stores `fancy_ptr<T>` objects, and the previous strategy accessed these objects via `const fancy_ptr<const T>` lvalues, which usually caused core language undefined behavior. Now `const_iterator` stores `fancy_ptr<const fancy_ptr<T>>` instead of `fancy_ptr<const fancy_ptr<const T>>`, and ABI break can happen when such two types have incompatible layouts. This is necessary for reducing undefined behavior and `constexpr` support for `deque` in C++26, and I currently don't want to provide any way to opt-out of that behavior. Also removes redundant identity `static_cast` before and after type change. The existing test coverage seems to be sufficient.
1 parent 78671db commit 6080007

File tree

2 files changed

+16
-9
lines changed

2 files changed

+16
-9
lines changed

libcxx/docs/ReleaseNotes/21.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ ABI Affecting Changes
114114
comparison between shared libraries, since all RTTI has the correct visibility now. There is no behaviour change on
115115
Clang.
116116

117+
- The ``const_iterator`` member type of ``std::deque`` is now corrected to hold a (possibly fancy) pointer to the
118+
(possibly fancy) pointer allocated in the internal map. E.g. when the allocators use fancy pointers, the internal map
119+
stores ``fancy_ptr<T>`` objects, and the previous strategy accessed these objects via ``const fancy_ptr<const T>``
120+
lvalues, which usually caused core language undefined behavior. Now ``const_iterator`` stores
121+
``fancy_ptr<const fancy_ptr<T>>`` instead of ``fancy_ptr<const fancy_ptr<const T>>``, and ABI break can happen when
122+
such two types have incompatible layouts. This is necessary for reducing undefined behavior and ``constexpr`` support
123+
for ``deque`` in C++26, so we do not provide any way to opt-out of that behavior.
124+
117125

118126
Build System Changes
119127
--------------------

libcxx/include/deque

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,12 @@ public:
504504
using pointer = typename __alloc_traits::pointer;
505505
using const_pointer = typename __alloc_traits::const_pointer;
506506

507-
using __pointer_allocator _LIBCPP_NODEBUG = __rebind_alloc<__alloc_traits, pointer>;
508-
using __const_pointer_allocator _LIBCPP_NODEBUG = __rebind_alloc<__alloc_traits, const_pointer>;
509-
using __map _LIBCPP_NODEBUG = __split_buffer<pointer, __pointer_allocator>;
510-
using __map_alloc_traits _LIBCPP_NODEBUG = allocator_traits<__pointer_allocator>;
511-
using __map_pointer _LIBCPP_NODEBUG = typename __map_alloc_traits::pointer;
512-
using __map_const_pointer _LIBCPP_NODEBUG = typename allocator_traits<__const_pointer_allocator>::const_pointer;
513-
using __map_const_iterator _LIBCPP_NODEBUG = typename __map::const_iterator;
507+
using __pointer_allocator _LIBCPP_NODEBUG = __rebind_alloc<__alloc_traits, pointer>;
508+
using __map _LIBCPP_NODEBUG = __split_buffer<pointer, __pointer_allocator>;
509+
using __map_alloc_traits _LIBCPP_NODEBUG = allocator_traits<__pointer_allocator>;
510+
using __map_pointer _LIBCPP_NODEBUG = typename __map_alloc_traits::pointer;
511+
using __map_const_pointer _LIBCPP_NODEBUG = typename allocator_traits<__pointer_allocator>::const_pointer;
512+
using __map_const_iterator _LIBCPP_NODEBUG = typename __map::const_iterator;
514513

515514
using reference = value_type&;
516515
using const_reference = const value_type&;
@@ -721,7 +720,7 @@ public:
721720
}
722721

723722
_LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
724-
__map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __start_ / __block_size);
723+
__map_const_pointer __mp = __map_.begin() + __start_ / __block_size;
725724
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size);
726725
}
727726

@@ -733,7 +732,7 @@ public:
733732

734733
_LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
735734
size_type __p = size() + __start_;
736-
__map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __p / __block_size);
735+
__map_const_pointer __mp = __map_.begin() + __p / __block_size;
737736
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size);
738737
}
739738

0 commit comments

Comments
 (0)