Таймер boost asio, завернутый в сопрограммы, вызывает SEGFAULT на clang-5.0

Следующий код вызывает SEGFAULT на clang-5.0 с включенной поддержкой сопрограмм. Вы можете запустить код онлайн здесь: wandbox скомпилированный код

Я использую параметры компилятора:

-stdlib=libc++ -fcoroutines-ts

Когда я запускаю его под GDB, это SEGFAULTs в async_await после coro.resume(); называется. Функция await_resume никогда не достигается. Я ожидаю, что это будет проблемой жизни объекта. Очень большой кусок кода компилируется и работает под MSVC 2017 без каких-либо проблем.

Выход программы:

i=0
Segmentation fault
Finish

Исходный код:

#define BOOST_THREAD_PROVIDES_FUTURE 
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION // Enables future::then 
#include <boost/thread.hpp> 
#include <boost/asio.hpp> 
#include <boost/asio/system_timer.hpp>

#include <experimental/coroutine>
#include <chrono>
#include <iostream>

namespace std
{
   namespace experimental
   {
      template <typename... Args>
      struct coroutine_traits<boost::future<void>, Args...> {
         struct promise_type {
            boost::promise<void> p;
            auto get_return_object() { return p.get_future(); }
            std::experimental::suspend_never initial_suspend() { return {}; }
            std::experimental::suspend_never final_suspend() { return {}; }
            void unhandled_exception(){}

            void return_void() { p.set_value(); }
         };
      };
   }
}

namespace asioadapt
{
   using namespace std::experimental;

   template <typename R> auto operator co_await(boost::future<R> &&f) {
      struct Awaiter {
         boost::future<R> &&input;
         boost::future<R> output;
         bool await_ready() { return false; }
         auto await_resume() { return output.get(); }
         void await_suspend(std::experimental::coroutine_handle<> coro) {
            input.then([this, coro](auto result_future) mutable{
               this->output = std::move(result_future);
               coro.resume();
            });
         }
      };
      return Awaiter{ static_cast<boost::future<R>&&>(f) };
   }

   template <typename R, typename P>
   auto async_await(boost::asio::system_timer &t, std::chrono::duration<R, P> d) {
      struct Awaiter
      {
         boost::asio::system_timer &t;
         std::chrono::duration<R, P> d;
         boost::system::error_code ec;

         bool await_ready() { return false; }
         void await_suspend(std::experimental::coroutine_handle<> coro) {
            t.expires_from_now(d);
            t.async_wait([this, &coro](auto ec) mutable {
               this->ec = ec;
               coro.resume();
            });
         }

         void await_resume() {
            if (ec)
               throw boost::system::system_error(ec);
         }
      };

      return Awaiter{ t, d };
   }
}

using namespace boost;
using namespace boost::asio;
using namespace std::chrono_literals;
using namespace asioadapt;

boost::future<void> sleepy(io_service &io, int &i) {
   system_timer timer(io);
   std::cout << "i=" << i << std::endl;

   co_await async_await(timer, 100ms);
   ++i;
   std::cout << "i=" << i << std::endl;

   co_await async_await(timer, 100ms);
   ++i;
   std::cout << "i=" << i << std::endl;

   co_await async_await(timer, 100ms);
   ++i;
   std::cout << "i=" << i << std::endl;
}


void test(){
   int i = 0;
   io_service io;
   auto future = sleepy(io, i);
   io.run();

   std::cout << "i=" << i << std::endl;
}


int main()
{
test();
}

1 ответ

Я пропустил функцию & в лямбда-захвате await_suspend. Таким образом, дескриптор coroutine_handle уничтожается после этого вызова.

Другие вопросы по тегам