From: Jonathan Wakely Date: Mon, 16 Dec 2024 17:42:24 +0000 (+0000) Subject: libstdc++: Fix std::deque::insert(pos, first, last) undefined behaviour [PR118035] X-Git-Tag: releases/gcc-12.5.0~207 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d14333852ebd77b898b3bf1030f9bf5152497345;p=thirdparty%2Fgcc.git libstdc++: Fix std::deque::insert(pos, first, last) undefined behaviour [PR118035] Inserting an empty range into a std::deque results in undefined calls to either std::copy, std::copy_backward, std::move, or std::move_backward. We call those algos with invalid arguments where the output range is the same as the input range, e.g. std::copy(first, last, first) which violates the preconditions for the algorithms. This fix simply returns early if there's nothing to insert. Most callers already ensure that we don't even call _M_range_insert_aux with an empty range, but some callers don't. Rather than checking for n == 0 in each of the callers, this just does the check once and uses __builtin_expect to treat empty insertions as unlikely. libstdc++-v3/ChangeLog: PR libstdc++/118035 * include/bits/deque.tcc (_M_range_insert_aux): Return immediately if inserting an empty range. * testsuite/23_containers/deque/modifiers/insert/118035.cc: New test. (cherry picked from commit b273e25e11c842a5729d0e03c85088cf5ba8e06c) --- diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index 03e0a505e14b..2ba5d7b8602f 100644 --- a/libstdc++-v3/include/bits/deque.tcc +++ b/libstdc++-v3/include/bits/deque.tcc @@ -601,6 +601,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER std::forward_iterator_tag) { const size_type __n = std::distance(__first, __last); + if (__builtin_expect(__n == 0, 0)) + return; + if (__pos._M_cur == this->_M_impl._M_start._M_cur) { iterator __new_start = _M_reserve_elements_at_front(__n); diff --git a/libstdc++-v3/testsuite/23_containers/deque/modifiers/insert/118035.cc b/libstdc++-v3/testsuite/23_containers/deque/modifiers/insert/118035.cc new file mode 100644 index 000000000000..a37d3dc3d04c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/modifiers/insert/118035.cc @@ -0,0 +1,26 @@ +// { dg-do run } + +#include +#include + +struct Sparks +{ + Sparks& operator=(const Sparks& s) + { + VERIFY( this != &s ); // This town ain't big enough for the both of us. + return *this; + } +}; + +void +test_pr118035() +{ + std::deque d(3, Sparks()); + Sparks s[1]; + d.insert(d.begin() + 1, s, s); +} + +int main() +{ + test_pr118035(); +}