Modify

Opened 3 years ago

Last modified 8 months ago

#10493 assigned Bugs

Since 1.56, any_range with non-reference references can cause UB

Reported by: nofitserov@… Owned by: Neil Groves
Milestone: Boost 1.64.0 Component: range
Version: Boost 1.62.0 Severity: Regression
Keywords: Cc: p.omta@…

Description

This must be related to #10360. This is a regression since 1.55.

When using any_range<T, category, T, ptrdiff_t>, mutable dereference() method returns mutable_reference_type_generator<T>::type, which becomes T&. So dereference() returns a dangling reference to an on-the-fly computed value.

See attached test case, which works with 1.55, and fails with -fsanitize=address on Clang 3.5 with 1.56.

#include <boost/range/any_range.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <cmath>
#include <iostream>

typedef boost::any_range<
    std::string,
    boost::forward_traversal_tag,
    std::string,
    std::ptrdiff_t
> range_t;

std::string f(std::string a)
{
    return a + "!";
}

int main()
{
    std::vector<std::string> v = {"a", "b"};
    range_t r = v | boost::adaptors::transformed(f);
    for (auto&& a : r)
        std::cout << a << std::endl;
    return 0;
}

Attachments (0)

Change History (6)

comment:1 Changed 3 years ago by Paul Omta <p.omta@…>

Cc: p.omta@… added

comment:2 Changed 3 years ago by Neil Groves

Milestone: To Be DeterminedBoost 1.58.0
Status: newassigned

comment:3 Changed 2 years ago by anonymous

Just reproduced it with boost 1.58 after migration from 1.55. I tried to play with it and found how to make it work.

Using const std::string instead of std::string, seems fix the problem

typedef boost::any_range<
    std::string,
    boost::forward_traversal_tag,
    const std::string,
    std::ptrdiff_t
> range_t;

I haven't digged into any_iterator sources but seems it behave differently when Reference is const

comment:4 Changed 2 years ago by kozlov.taras@…

Forget to add email in previous comment

comment:5 Changed 2 years ago by Tobias Reh <treh@…>

Still present in 1.59.0

The problem is becoming more visible with MSVC++2015 because the compiler is better in detecting dangling references and emitting errors for them. To hard code those checks, just add the following assert into every dereference() method in range/detail/any_iterator_wrapper.hpp:

static_assert(
   !std::is_lvalue_reference<reference>::value 
   || std::is_lvalue_reference<decltype(*m_it)>::value,
   "dangling ref"
);

A little bit of digging in the headers shows that the problem lies in range/detail/any_iterator_interface.hpp, where any_incrementable_iterator_interface's

typedef Reference reference;

was changed in 1.56.0 to

typedef typename mutable_reference_type_generator<
    Reference
>::type reference;

Rolling this back solves the problem for our codebase. Any possibilities of having this fixed soon?

comment:6 Changed 8 months ago by wslcdg@…

Milestone: Boost 1.58.0Boost 1.64.0
Version: Boost 1.56.0Boost 1.62.0

Problem still exists boost 1.62

Modify Ticket

Change Properties
Set your email in Preferences
Action
as assigned The owner will remain Neil Groves.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.