libstdc++: fix a dangling reference crash in ranges::is_permutation [PR118160]
The code was caching the result of `invoke(proj, *it)` in a local `auto &&` variable. The problem is that this may create dangling references, for instance in case `proj` is `std::identity` (the common case) and `*it` produces a prvalue: lifetime extension does not apply here due to the expressions involved. Instead, store (and lifetime-extend) the result of `*it` in a separate variable, then project that variable. While at it, also forward the result of the projection to the predicate, so that the predicate can act on the proper value category. libstdc++-v3/ChangeLog: PR libstdc++/118160 PR libstdc++/100249 * include/bits/ranges_algo.h (__is_permutation_fn): Avoid a dangling reference by storing the result of the iterator dereference and the result of the projection in two distinct variables, in order to lifetime-extend each one. Forward the projected value to the predicate. * testsuite/25_algorithms/is_permutation/constrained.cc: Add a test with a range returning prvalues. Test it in a constexpr context, in order to rely on the compiler to catch UB. Signed-off-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
parent
6e758f378a
commit
2a2bd96d0d
2 changed files with 18 additions and 2 deletions
|
@ -567,9 +567,12 @@ namespace ranges
|
|||
|
||||
for (auto __scan = __first1; __scan != __last1; ++__scan)
|
||||
{
|
||||
auto&& __proj_scan = std::__invoke(__proj1, *__scan);
|
||||
auto&& __scan_deref = *__scan;
|
||||
auto&& __proj_scan =
|
||||
std::__invoke(__proj1, std::forward<decltype(__scan_deref)>(__scan_deref));
|
||||
auto __comp_scan = [&] <typename _Tp> (_Tp&& __arg) -> bool {
|
||||
return std::__invoke(__pred, __proj_scan,
|
||||
return std::__invoke(__pred,
|
||||
std::forward<decltype(__proj_scan)>(__proj_scan),
|
||||
std::forward<_Tp>(__arg));
|
||||
};
|
||||
if (__scan != ranges::find_if(__first1, __scan,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_iterators.h>
|
||||
|
||||
|
@ -76,10 +77,22 @@ test03()
|
|||
while (std::next_permutation(std::begin(cx), std::end(cx)));
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
test04() // PR118160, do not create dangling references
|
||||
{
|
||||
int x[] = { 4, 3, 2, 1 };
|
||||
auto y = std::views::iota(1, 5);
|
||||
return ranges::is_permutation(x, y) && ranges::is_permutation(y, x);
|
||||
}
|
||||
|
||||
static_assert(test04());
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
VERIFY( test04() );
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue