I am trying to debug a larger program using boost asio that runs for a while and then crashes is various ways. I have tried to locate the bug using Valgrind and have reproduced a minimal example with a nested boost::asio::spawn where Valgrind says there is an invalid read.
The example is:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
int main()
{
boost::asio::io_context io_context;
boost::asio::spawn(io_context,
[&](boost::asio::yield_context yield)
{
std::cout<<"Spawn #1"<<std::endl;
boost::asio::spawn(yield, // Have also tried with io_context
[](boost::asio::yield_context yield2)
{
std::cout<<"Spawn #2"<<std::endl;
});
});
io_context.run();
return 0;
}
Running the example with valgrind gives:
$ valgrind ./nestspawn
==377032== Memcheck, a memory error detector
==377032== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==377032== Using Valgrind-3.23.0.GIT and LibVEX; rerun with -h for copyright info
==377032== Command: ./nestspawn
==377032==
==377032== Warning: client switching stacks? SP change: 0x1ffefff948 --> 0x4e0d6f8
==377032== to suppress, use: --max-stackframe=137340330576 or greater
==377032== Warning: client switching stacks? SP change: 0x4e0d408 --> 0x1ffefff948
==377032== to suppress, use: --max-stackframe=137340331328 or greater
==377032== Warning: client switching stacks? SP change: 0x1ffefff7a8 --> 0x4e0d408
==377032== to suppress, use: --max-stackframe=137340330912 or greater
==377032== further instances of this message will not be shown.
Spawn #1
==377032== Invalid read of size 8
==377032== at 0x1129B6: void boost::coroutines::detail::trampoline_pull<boost::coroutines::detail::pull_coroutine_object<boost::coroutines::push_coroutine<void>, void, boost::asio::detail::spawned_coroutine_thread::entry_point<boost::asio::detail::old_spawn_entry_point<boost::asio::any_io_executor, main::{lambda(boost::asio::basic_yield_context<boost::asio::any_io_executor>)#1}::operator()(boost::asio::basic_yield_context<boost::asio::any_io_executor>) const::{lambda(boost::asio::basic_yield_context<boost::asio::any_io_executor>)#1}, void (*)()> >, boost::coroutines::basic_standard_stack_allocator<boost::coroutines::stack_traits> > >(boost::context::detail::transfer_t) (trampoline_pull.hpp:32)
==377032== by 0x4CFC1F6: make_fcontext (in /usr/local/lib/libboost_context.so.1.85.0)
==377032== Address 0x4e0d120 is 63,760 bytes inside a block of size 65,536 alloc'd
==377032== at 0x484880F: malloc (vg_replace_malloc.c:446)
==377032== by 0x124D93: boost::coroutines::basic_standard_stack_allocator<boost::coroutines::stack_traits>::allocate(boost::coroutines::stack_context&, unsigned long) (standard_stack_allocator.hpp:52)
==377032== by 0x112B0F: boost::coroutines::pull_coroutine<void>::pull_coroutine<boost::asio::detail::spawned_coroutine_thread::entry_point<boost::asio::detail::old_spawn_entry_point<boost::asio::strand<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >, main::{lambda(boost::asio::basic_yield_context<boost::asio::any_io_executor>)#1}, void (*)()> > >(boost::asio::detail::spawned_coroutine_thread::entry_point<boost::asio::detail::old_spawn_entry_point<boost::asio::strand<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >, main::{lambda(boost::asio::basic_yield_context<boost::asio::any_io_executor>)#1}, void (*)()> >&&, boost::coroutines::attributes const&) (asymmetric_coroutine.hpp:1474)
.... continues
As far as I know it is legal to use nested spawn. So what is wrong in the code?
I am trying to debug a larger program using boost asio that runs for a while and then crashes is various ways. I have tried to locate the bug using Valgrind and have reproduced a minimal example with a nested boost::asio::spawn where Valgrind says there is an invalid read.
The example is:
Running the example with valgrind gives:
As far as I know it is legal to use nested spawn. So what is wrong in the code?
Best regards