Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::any_range with optimization level -O2 causes crash

Tags:

c++

boost

What is the problem with this code:

#include <iostream>
#include <vector>

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


using namespace boost::adaptors;


using Range =
  boost::any_range<
    int,
    boost::forward_traversal_tag,
    int,
    std::ptrdiff_t>;


void magic(const Range &) {}


int main()
{
  std::vector<int> xs{0, 1, 2};

  auto ys = xs | transformed([](auto x) { return x; });

  const Range zs = ys;
  std::vector<int> us{boost::begin(zs), boost::end(zs)};
  magic(us);

  return 0;
}

Complie:

c++ -g -std=c++14 -O2 main.cpp

Run and get segfault.

But when I compile with lower optimization level, then everything is ok.

gdb output:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004011a5 in boost::range_detail::any_iterator<int, boost::iterators::forward_traversal_tag, int, long, boost::any_iterator_buffer<64ul> >::dereference (this=<optimized out>) at /usr/include/boost/range/detail/any_iterator.hpp:512
512                     return m_impl->dereference();

Is this boost::any_range bug, or I misuse the library?

Program also crashes if I compile it this way:

c++ -g -std=c++14 -O1 -fisolate-erroneous-paths-dereference main.cpp

The program below crashes too, if I compile it with options -O1 -fisolate-erroneous-paths-dereference:

#include <iostream>
#include <vector>

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


using namespace boost::adaptors;


using Range =
  boost::any_range<
    int,
    boost::forward_traversal_tag,
    int &,
    std::ptrdiff_t>;


void magic(const Range &xs) {
  for (auto x: xs) { std::cout << xs; }
}


int main()
{
  std::vector<int> xs{0, 1, 2};
  auto ys = xs | transformed([](auto x) { return x; });
  magic(ys);
  return 0;
}
like image 240
nicolai Avatar asked Jan 05 '23 11:01

nicolai


1 Answers

This is boost bug 10493, related to 10360, which was introduced in 1.56 (2014-08) and was only finally fixed in 1.74 (2020-08) via fix PR #94

Until 1.74, the problem is that instead of just using your reference type, it wraps it in mutable_reference_type_generator, which prevents you from being able to return a temporary. That is, when you write:

using Range =
  boost::any_range<
    int,
    boost::forward_traversal_tag,
    int,
    std::ptrdiff_t>;

You're explicitly specifying your reference type to be int, not int&, because your range is basically an input range. But the boost internals are changing it to int& anyway, so you dangle. When you write const int intsead of int, the type trait doesn't add the reference, so you actually do end up with const int.

like image 142
Barry Avatar answered Jan 13 '23 04:01

Barry