chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.72k stars 1.19k forks source link

In class cancellation_signal (cancellation_signal.hpp) handler_ is freed but emit is called after being freed and causes a crash #1400

Open sldr opened 6 months ago

sldr commented 6 months ago

Environment Info

This is happening with Asio V1.29.0 (non-Boost) on Windows 10. I have also tried using the code from master and it still causes the crash.

I compile with Visual Studio 2022 V17.8.3 and /std:C++20. I am using coroutines and the following experimental classes:

Brief Description of Asio Usage

A std::thread is using the asio::concurrent_channel to send a std::sting to coroutines running in an asio::thread_pool. The thread pool size is 2. An asio coroutine is started using asio::co_spawn that after opening a socket does a

co_await (s->async_wait(asio::ip::tcp::socket::wait_read, asio::use_awaitable) || concurrent_channel->async_receive(asio::use_awaitable))

and then reads data from socket or processes std::string from concurrent_channel.

Crash Details

This is emit method from cancellationsignal where handler is nullptr and the dereference of handler_ is done for call method.:

  /// Emits the signal and causes invocation of the slot's handler, if any.
  void emit(cancellation_type_t type)
  {
    if (handler_)
      handler_->call(type);
  }

Visual Studio showing the nullptr value for handler_: image

Call Stack

``` ucrtbased.dll!issue_debug_notification(const wchar_t * const message) Line 28 ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message) Line 154 ucrtbased.dll!abort() Line 61 vcruntime140d.dll!_purecall() Line 30 MyProg.exe!asio::cancellation_signal::emit(asio::cancellation_type type) Line 99 MyProg.exe!asio::cancellation_state::impl,asio::cancellation_filter<1>>::operator()(asio::cancellation_type in) Line 222 MyProg.exe!asio::detail::cancellation_handler,asio::cancellation_filter<1>>>::call(asio::cancellation_type type) Line 56 MyProg.exe!asio::cancellation_signal::emit(asio::cancellation_type type) Line 99 MyProg.exe!asio::detail::co_spawn_cancellation_handler,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,void>::operator()(asio::cancellation_type type) Line 279 MyProg.exe!asio::detail::cancellation_handler,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,void>>::call(asio::cancellation_type type) Line 56 MyProg.exe!asio::cancellation_signal::emit(asio::cancellation_type type) Line 99 MyProg.exe!asio::experimental::detail::parallel_group_op_handler<0,asio::experimental::wait_for_one_success,asio::detail::awaitable_async_op_handler,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>::operator()(std::exception_ptr ) Line 225 MyProg.exe!asio::detail::co_spawn_entry_point::__l2::::operator()() Line 207 MyProg.exe!asio::detail::binder0<`asio::detail::co_spawn_entry_point,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::>::operator()() Line 56 MyProg.exe!asio::detail::executor_function::complete,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::>,std::allocator>(asio::detail::executor_function::impl_base * base, bool call) Line 112 MyProg.exe!asio::detail::executor_function::operator()() Line 62 MyProg.exe!asio::io_context::basic_executor_type,4>::execute(asio::detail::executor_function && f) Line 282 MyProg.exe!asio::execution::detail::any_executor_base::execute_ex,4>>(const asio::execution::detail::any_executor_base & ex, asio::detail::executor_function && f) Line 900 MyProg.exe!asio::execution::detail::any_executor_base::execute,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::>>(asio::detail::binder0<`asio::detail::co_spawn_entry_point,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::> && f) Line 680 MyProg.exe!asio::detail::initiate_dispatch_with_executor::operator()<`asio::detail::co_spawn_entry_point,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::>(asio::detail::co_spawn_entry_point::__l2:: && handler, void * __formal, void * __formal) Line 105 MyProg.exe!??@e461c3c8f1d18d37e393182ac754932e@(asio::detail::initiate_dispatch_with_executor && initiation, asio::detail::co_spawn_entry_point::__l2:: && token) Line 275 MyProg.exe!asio::async_initiate<`asio::detail::co_spawn_entry_point,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::,void __cdecl(void),asio::detail::initiate_dispatch_with_executor>(asio::detail::initiate_dispatch_with_executor && initiation, asio::detail::co_spawn_entry_point::__l2:: & token) Line 573 MyProg.exe!asio::dispatch,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>'::`2'::>(const asio::any_io_executor & ex, asio::detail::co_spawn_entry_point::__l2:: && token, int __formal) Line 155 MyProg.exe!asio::detail::co_spawn_entry_point,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function>(asio::awaitable * $FP2, asio::detail::co_spawn_state,std::exception_ptr,std::exception_ptr,std::string),asio::any_io_executor>,asio::deferred_async_operation,asio::detail::awaitable_as_function>,asio::deferred_async_operation,asio::detail::awaitable_as_function>>,asio::any_io_executor,asio::detail::awaitable_as_function,void> s) Line 203 MyProg.exe!std::coroutine_handle::resume() Line 85 MyProg.exe!asio::detail::awaitable_frame_base::resume() Line 501 MyProg.exe!asio::detail::awaitable_thread::pump() Line 769 MyProg.exe!asio::detail::awaitable_handler::operator()(const std::error_code & ec) Line 93 MyProg.exe!asio::detail::binder1,std::error_code>::operator()() Line 116 MyProg.exe!asio::detail::handler_work,asio::any_io_executor,void>::complete,std::error_code>>(asio::detail::binder1,std::error_code> & function, asio::detail::awaitable_handler & handler) Line 433 MyProg.exe!asio::detail::win_iocp_wait_op,asio::any_io_executor>::do_complete(void * owner, asio::detail::win_iocp_operation * base, const std::error_code & result_ec, unsigned __int64 __formal) Line 112 MyProg.exe!asio::detail::win_iocp_operation::complete(void * owner, const std::error_code & ec, unsigned __int64 bytes_transferred) Line 47 MyProg.exe!asio::detail::win_iocp_socket_service_base::reactor_op_cancellation::do_complete(void * owner, asio::detail::win_iocp_operation * base, const std::error_code & result_ec, unsigned __int64 bytes_transferred) Line 762 MyProg.exe!asio::detail::win_iocp_operation::complete(void * owner, const std::error_code & ec, unsigned __int64 bytes_transferred) Line 47 MyProg.exe!asio::detail::win_iocp_io_context::do_one(unsigned long msec, asio::detail::win_iocp_thread_info & this_thread, std::error_code & ec) Line 475 MyProg.exe!asio::detail::win_iocp_io_context::run(std::error_code & ec) Line 205 MyProg.exe!asio::io_context::run() Line 63 MyProg.exe!pac::PortASIOCtx::getIOContext::__l48::::operator()() Line 998 MyProg.exe!asio::detail::binder0<`pac::PortASIOCtx::getIOContext'::`48'::>::operator()() Line 56 MyProg.exe!asio::detail::executor_op>,std::allocator,asio::detail::scheduler_operation>::do_complete(void * owner, asio::detail::scheduler_operation * base, const std::error_code & __formal, unsigned __int64 __formal) Line 69 MyProg.exe!asio::detail::scheduler_operation::complete(void * owner, const std::error_code & ec, unsigned __int64 bytes_transferred) Line 40 MyProg.exe!asio::detail::scheduler::do_run_one(asio::detail::conditionally_enabled_mutex::scoped_lock & lock, asio::detail::scheduler_thread_info & this_thread, const std::error_code & ec) Line 493 MyProg.exe!asio::detail::scheduler::run(std::error_code & ec) Line 209 MyProg.exe!asio::thread_pool::thread_function::operator()() Line 38 MyProg.exe!asio::detail::win_thread::func::run() Line 122 MyProg.exe!asio::detail::win_thread_function(void * arg) Line 126 ucrtbased.dll!thread_start(void * const parameter) Line 97 kernel32.dll!BaseThreadInitThunk() Unknown ntdll.dll!RtlUserThreadStart() Unknown ```

Notes

Thanks, SLDR (Stephen L. De Rudder)