Can I co_await an operation executed by one io_context in a coroutine executed by another in Asio? - c++

I have an HTTP server library writen by Asio with one io_context per thread model. It has an io_context_pool which retrieves one io_context orderly. So when the server starts, io_context #1 will be used to execute the acceptor and io_context #2 will be used for the first connection and io_context #3 will be with the second and so on.
It also wait for signal to call the io_context.stop() orderly to stop the server and it works well.
I would like to refactor it with C++20 coroutine. I've almost finished but I found that if signal reveived to call io_context.stop(), heap used after free will be reported by sanitizer. I've no idea how to solve this.
Here is a simplified example:
constexpr int wait_second = 2;
constexpr int run_second = 3;
asio::awaitable<void> co_main(asio::io_context& other_ctx){
asio::steady_timer timer(other_ctx);
timer.expires_after(std::chrono::seconds(wait_second));
co_await timer.async_wait(asio::use_awaitable);
std::cout<<"timer"<<std::endl;
}
int main() {
asio::io_context ctx;
asio::io_context other_ctx;
asio::executor_work_guard<asio::io_context::executor_type> g1(ctx.get_executor());
asio::executor_work_guard<asio::io_context::executor_type> g2(other_ctx.get_executor());
asio::co_spawn(ctx, co_main(other_ctx), asio::detached);
std::thread([&]{
std::this_thread::sleep_for(std::chrono::seconds(run_second));
ctx.stop();
other_ctx.stop();
}).detach();
std::thread t1([&]{ctx.run();});
std::thread t2([&]{other_ctx.run();});
t1.join();
t2.join();
return 0;
}
The coroutine co_main is executed by ctx but the timer in it is executed by other_ctx. The wait_second represents the waiting duration of the timer while run_second represent after how many seconds the ctx and io_context will be stopped.
If the wait_second is less than run_second, everything works fine but if wait_second is longer, heap used after free will be reported by sanitizer. So is this the right way to use asio::awaitable? Can I mix use the io_context with coroutine?

Yes this usage is fine. Not optimal, but fine.
The thing to note about binding IO objects to an executor is that it mostly serves two purposes:
firstly it indicates which execution context holds the service instance for the IO object's implementation
secondly it serves as the default(!) executor for completion handlers
Note that 1. implies that it may incur more overhead than sharing the context, and 2. means that there is little behavioral difference in this case. It's the default only, so the awaitable's coro executor overrides it here. This may not be as you expected. See e.g. this similar question Boost asio steady_timer work on different strand than intended
What's the sanitizer issue
It's a lifetime issue. Let's instrument a bit and use BOOST_ASIO_ENABLE_HANDLER_TRACKING as well:
#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;
namespace asio = boost::asio;
constexpr auto wait_for = 200ms, run_for = 300ms;
asio::awaitable<void> co_main(asio::io_context& other_ctx){
asio::steady_timer timer{other_ctx.get_executor(), wait_for};
co_await timer.async_wait(asio::use_awaitable);
std::cout << "timer" << std::endl;
}
int main() {
{
asio::io_context other_ctx;
{
asio::io_context ctx;
//auto g1 = ctx.get_executor();
//auto g2 = other_ctx.get_executor();
asio::co_spawn(ctx, co_main(other_ctx), asio::detached);
std::thread stopper([&] {
std::this_thread::sleep_for(run_for);
ctx.stop();
other_ctx.stop();
});
std::thread t1([&] { ctx.run(); });
std::thread t2([&] { other_ctx.run(); });
stopper.join();
t1.join();
t2.join();
std::cout << "All joined" << std::endl;
std::cout << "ctx: " << &ctx << std::endl;
std::cout << "other_ctx: " << &other_ctx << std::endl;
}
std::cout << "ctx destructed" << std::endl;
}
std::cout << "other_ctx destructed" << std::endl;
}
After all threads are done (and joined), the destructor of other_ctx abandons all operations in the operation queue. Some of the completions are bound to the executor of ctx (because of the coro, see above) which is already gone. This leads to the use-after-scope (truncating for SO):
#asio|1661689229.839262|0^1|in 'co_spawn_entry_point' (/home/sehe/custom/superboost/boost/asio/impl/co_spawn.hpp:154)
#asio|1661689229.839262|0*1|io_context#0x7ffe27cf56a0.execute
#asio|1661689229.839715|>1|
#asio|1661689229.839961|1*2|deadline_timer#0x6110000000a0.async_wait
#asio|1661689229.839986|<1|
All joined
ctx: 0x7ffe27cf56a0
other_ctx: 0x7ffe27cf5680
ctx destructed
#asio|1661689230.139986|2*3|io_context#0x7ffe27cf56a0.execute
=================================================================
==16129==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffe27cf56a8 at pc 0x55bace9962f6 bp 0x7ffe27cf4270 sp 0x7ffe27cf4260
READ of size 8 at 0x7ffe27cf56a8 thread T0
#0 0x55bace9962f5 in void boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>::....hpp:319
#1 0x55bace968067 in void boost::asio::execution::detail::any_executor_base::execute<boost::asio::d....hpp:611
#2 0x55bace968067 in std::enable_if<boost_asio_execution_execute_fn::call_traits<boost_asio_executi....hpp:208
#3 0x55bace968067 in void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_exec....hpp:122
#4 0x55bace968067 in void boost::asio::detail::completion_handler_async_result<boost::asio::detail:....hpp:482
#5 0x55bace968067 in boost::asio::constraint<boost::asio::detail::async_result_has_initiate_memfn<b....hpp:896
#6 0x55bace968067 in auto boost::asio::post<boost::asio::any_io_executor, boost::asio::detail::awai....hpp:242
#7 0x55bace969443 in boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitabl....hpp:673
#8 0x55bace99ecb0 in boost::asio::detail::awaitable_handler_base<boost::asio::any_io_executor, void....hpp:29
#9 0x55bace99ecb0 in boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::sy....hpp:78
#10 0x55bace99ecb0 in boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::as....hpp:139
#11 0x55bace99ecb0 in boost::asio::detail::wait_handler<boost::asio::detail::awaitable_handler<boos....hpp:67
#12 0x55bace91be12 in boost::asio::detail::scheduler_operation::destroy() /home/sehe/custom/superbo....hpp:45
#13 0x55bace91be12 in void boost::asio::detail::op_queue_access::destroy<boost::asio::detail::sched....hpp:47
#14 0x55bace91be12 in boost::asio::detail::op_queue<boost::asio::detail::scheduler_operation>::~op_....hpp:81
#15 0x55bace91be12 in boost::asio::detail::scheduler::abandon_operations(boost::asio::detail::op_qu....ipp:444
#16 0x55bace91be12 in boost::asio::detail::epoll_reactor::shutdown() /home/sehe/custom/superboost/b....ipp:92
#17 0x55bace8ebc8c in boost::asio::detail::service_registry::shutdown_services() /home/sehe/custom/....ipp:44
#18 0x55bace8ebc8c in boost::asio::execution_context::shutdown() /home/sehe/custom/superboost/boost....ipp:41
#19 0x55bace8ebc8c in boost::asio::execution_context::~execution_context() /home/sehe/custom/superb....ipp:34
#20 0x55bace88d684 in boost::asio::io_context::~io_context() /home/sehe/custom/superboost/boost/asi....ipp:56
#21 0x55bace88d684 in main /home/sehe/Projects/stackoverflow/test.cpp:16
#22 0x7efe676d0c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#23 0x55bace88e859 in _start (/home/sehe/Projects/stackoverflow/build/sotest+0x1a5859)
Address 0x7ffe27cf56a8 is located in stack of thread T0 at offset 904 in frame
#0 0x55bace88bd2f in main /home/sehe/Projects/stackoverflow/test.cpp:14
This frame has 34 object(s):
// ... skipped
[128, 136) '<unknown>'
[160, 168) 'stopper' (line 24)
[192, 200) 't1' (line 30)
[224, 232) '<unknown>'
[256, 264) 't2' (line 31)
[288, 296) '<unknown>'
// ... skipped
[832, 840) '<unknown>'
[864, 880) 'other_ctx' (line 16)
[896, 912) 'ctx' (line 18) <== Memory access at offset 904 is inside this variable
[928, 944) '<unknown>'
[960, 1016) '<unknown>'
[1056, 1112) '<unknown>'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /home/sehe/custom/superboost/boost/asio/impl/io_context.hpp:319 in void boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>::execute<boost::asio::detail::executor_function>(boost::asio::detail::executor_function&&) const
Shadow bytes around the buggy address:
0x100044f96a80: f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2
0x100044f96a90: f8 f2 f2 f2 f8 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2
0x100044f96aa0: 00 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2
0x100044f96ab0: f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2
0x100044f96ac0: f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2
=>0x100044f96ad0: 00 00 f2 f2 f8[f8]f2 f2 f8 f8 f2 f2 f8 f8 f8 f8
0x100044f96ae0: f8 f8 f8 f2 f2 f2 f2 f2 f8 f8 f8 f8 f8 f8 f8 f3
0x100044f96af0: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x100044f96b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100044f96b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100044f96b20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==16129==ABORTING
Ironically, flipping the order of executor destruction doesn't help:
{
asio::io_context ctx;
{
asio::io_context other_ctx;
// ... skiped unchanged
}
std::cout << "other_ctx destructed" << std::endl;
}
std::cout << "ctx destructed" << std::endl;
Now we get the inverse dependency: after all threads have joined, the destructor of other_ctx correctly queues completion for the async_wait on ctx. But once ctx destructor shuts down its services, it will destroy the coro stack frame, which includes the timer object which ... has a stale reference to the other_ctx destructor.
#asio|1661689960.225134|0^1|in 'co_spawn_entry_point' (/home/sehe/custom/superboost/boost/asio/impl/co_spawn.hpp:154)
#asio|1661689960.225134|0*1|io_context#0x7ffd9e839d80.execute
#asio|1661689960.225576|>1|
#asio|1661689960.225876|1*2|deadline_timer#0x6110000000a0.async_wait
#asio|1661689960.225899|<1|
All joined
ctx: 0x7ffd9e839d80
other_ctx: 0x7ffd9e839da0
#asio|1661689960.525759|2*3|io_context#0x7ffd9e839d80.execute
#asio|1661689960.525773|~2|
other_ctx destructed
/usr/include/c++/10/coroutine:128: runtime error: member call on null pointer of type 'struct steady_timer'
/home/sehe/custom/superboost/boost/asio/basic_waitable_timer.hpp:382:3: runtime error: member access within null pointer of type 'struct basic_waitable_timer'
/home/sehe/custom/superboost/boost/asio/basic_waitable_timer.hpp:382:3: runtime error: member call on null pointer of type 'struct io_object_impl'
/home/sehe/custom/superboost/boost/asio/detail/io_object_impl.hpp:97:5: runtime error: member access within null pointer of type 'struct io_object_impl'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==22649==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x558135f6b18f bp 0x7ffd9e837d10 sp 0x7ffd9e837a00 T0)
==22649==The signal is caused by a READ memory access.
==22649==Hint: address points to the zero page.
#0 0x558135f6b18f in boost::asio::detail::io_object_impl<boost::asio::detail::deadline_timer_service<bo....hpp:97
#1 0x558135e6d07a in boost::asio::basic_waitable_timer<std::chrono::_V2::steady_clock, boost::asio::wai....hpp:382
#2 0x558135e6d07a in co_main(boost::asio::io_context&) [clone .actor] /home/sehe/custom/superboost/boos....hpp:380
#3 0x558135f0b5e9 in std::__n4861::coroutine_handle<void>::destroy() const /usr/include/c++/10/coroutine:128
#4 0x558135f0b5e9 in boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::destroy()....hpp:496
#5 0x558135f0b5e9 in boost::asio::awaitable<void, boost::asio::any_io_executor>::~awaitable() /home/seh....hpp:77
#6 0x558135f0b5e9 in boost::asio::awaitable<boost::asio::detail::awaitable_thread_entry_point, boost::a....actor] /home/sehe/custom/superboost/boost/asio/impl/co_spawn.hpp:183
#7 0x558135ea6d1d in std::__n4861::coroutine_handle<void>::destroy() const /usr/include/c++/10/coroutine:128
#8 0x558135ea6d1d in boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::destroy()....hpp:496
#9 0x558135ea6d1d in boost::asio::awaitable<boost::asio::detail::awaitable_thread_entry_point, boost::a....hpp:77
#10 0x558135ea6d1d in boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitable_t....hpp:674
#11 0x558135ea6d1d in boost::asio::detail::binder0<boost::asio::detail::awaitable_thread<boost::asio::a....hpp:32
#12 0x558135ea6d1d in void boost::asio::detail::executor_function::complete<boost::asio::detail::binder....hpp:110
#13 0x558135f6ecfb in boost::asio::detail::executor_function::~executor_function() /home/sehe/custom/su....hpp:55
#14 0x558135f6ecfb in boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::all....hpp:62
#15 0x558135ec4893 in boost::asio::detail::scheduler_operation::destroy() /home/sehe/custom/superboost/....hpp:45
#16 0x558135ec4893 in boost::asio::detail::scheduler::shutdown() /home/sehe/custom/superboost/boost/asi....ipp:176
#17 0x558135ebfc8c in boost::asio::detail::service_registry::shutdown_services() /home/sehe/custom/supe....ipp:44
#18 0x558135ebfc8c in boost::asio::execution_context::shutdown() /home/sehe/custom/superboost/boost/asi....ipp:41
#19 0x558135ebfc8c in boost::asio::execution_context::~execution_context() /home/sehe/custom/superboost....ipp:34
#20 0x558135e61684 in boost::asio::io_context::~io_context() /home/sehe/custom/superboost/boost/asio/im....ipp:56
#21 0x558135e61684 in main /home/sehe/Projects/stackoverflow/test.cpp:16
#22 0x7fbd0bd07c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#23 0x558135e62859 in _start (/home/sehe/Projects/stackoverflow/build/sotest+0x1a5859)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/sehe/custom/superboost/boost/asio/detail/io_object_impl.hpp:97 in boost::asio::detail::io_object_impl<boost::asio::detail::deadline_timer_service<boost::asio::detail::chrono_time_traits<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> > >, boost::asio::any_io_executor>::~io_object_impl()
==22649==ABORTING
The problem appears to be that the coro frame outlives the lifetime of other_ctx here.
Conclusion
You have to avoid destruction of both contexts from inter-depending cyclically. This practically means avoiding uncompleted operations in their operation queues.
It's good to note that the problems mostly start with using io_context::stop() to stop context mid-operation. In addition, there doesn't currently seem to be a reason run() the other_ctx in the first place.
Consider using async completion / awaitable operators with cancellation.

Related

Google breakpad crashes when run under a debugger

We have a problem where initializing the Google Breakpad exception handler errors out when the program is run under lldb, but not when run normally from the shell.
The system is MacOS 13 (Ventura) and the IDE is Visual Studio Code.
The code below fails on a call to init():
namespace crashhandler {
static std::unique_ptr<google_breakpad::ExceptionHandler> pExceptionHandler;
namespace {
bool DumpCallback(const char* dump_dir, const char* minidump_id, void*, bool success) {
if (success)
printf("Application crashed. Breakpad Crash Handler created a dump at location %s/%s.dmp\n",
dump_dir, minidump_id);
else
printf("Application crashed. Breakpad Crash Handler failed to create a dump");
fflush(stdout);
return success;
}
} // namespace
void init(const std::string& reportPath) // <-- crash happens when calling this function
{
if (pExceptionHandler)
return;
pExceptionHandler.reset(
new google_breakpad::ExceptionHandler(reportPath, nullptr, DumpCallback, nullptr, true, nullptr));
}
} // namespace crashhandler
The debug console shows:
=================================================================
==5060==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x00016fdfee00 at pc 0x000100ac9030 bp 0x00016ff11540 sp 0x00016ff10d08
READ of size 4608 at 0x00016fdfee00 thread T2
#0 0x100ac902c in wrap_write+0x15c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1902c)
#1 0x100109f08 in google_breakpad::UntypedMDRVA::Copy(unsigned int, void const*, unsigned long)+0x54 (my_server:arm64+0x100109f08)
#2 0x10010ce14 in google_breakpad::MinidumpGenerator::WriteStackFromStartAddress(unsigned long long, MDMemoryDescriptor*)+0xf8 (my_server:arm64+0x10010ce14)
#3 0x10010d244 in google_breakpad::MinidumpGenerator::WriteThreadStream(unsigned int, MDRawThread*)+0x100 (my_server:arm64+0x10010d244)
#4 0x10010c04c in google_breakpad::MinidumpGenerator::WriteThreadListStream(MDRawDirectory*)+0xfc (my_server:arm64+0x10010c04c)
#5 0x10010bd20 in google_breakpad::MinidumpGenerator::Write(char const*)+0xc8 (my_server:arm64+0x10010bd20)
#6 0x10010adc0 in google_breakpad::ExceptionHandler::WriteMinidumpWithException(int, int, int, __darwin_ucontext64*, unsigned int, bool, bool)+0x160 (my_server:arm64+0x10010adc0)
#7 0x10010af1c in google_breakpad::ExceptionHandler::WaitForMessage(void*)+0x104 (my_server:arm64+0x10010af1c)
#8 0x1a330a068 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x7068)
#9 0x1a3304e28 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1e28)
Address 0x00016fdfee00 is located in stack of thread T0 at offset 0 in frame
#0 0x1000034cc in main main.cpp:36
This frame has 10 object(s):
[32, 56) 'reportPath' (line 39) <== Memory access at offset 0 partially underflows this variable
[96, 120) 'ref.tmp' (line 40) <== Memory access at offset 0 partially underflows this variable
[160, 208) 'parser' (line 43) <== Memory access at offset 0 partially underflows this variable
[240, 264) 'configPath' (line 45) <== Memory access at offset 0 partially underflows this variable
[304, 320) 'ref.tmp12' (line 46) <== Memory access at offset 0 partially underflows this variable
[336, 360) 'agg.tmp' <== Memory access at offset 0 partially underflows this variable
[400, 416) 'ref.tmp30' (line 57) <== Memory access at offset 0 partially underflows this variable
[432, 456) 'agg.tmp42' <== Memory access at offset 0 partially underflows this variable
[496, 520) 'agg.tmp80' <== Memory access at offset 0 partially underflows this variable
[560, 568) 'ref.tmp86' (line 74) <== Memory access at offset 0 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1902c) in wrap_write+0x15c
Shadow bytes around the buggy address:
0x00702dfdfd70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfd90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfda0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfdb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x00702dfdfdc0:[f1]f1 f1 f1 00 00 00 f2 f2 f2 f2 f2 f8 f8 f8 f2
0x00702dfdfdd0: f2 f2 f2 f2 f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 f8 f8
0x00702dfdfde0: f8 f2 f2 f2 f2 f2 f8 f8 f2 f2 00 00 00 f2 f2 f2
0x00702dfdfdf0: f2 f2 f8 f8 f2 f2 00 00 00 f2 f2 f2 f2 f2 00 00
0x00702dfdfe00: 00 f2 f2 f2 f2 f2 f8 f3 f3 f3 f3 f3 00 00 00 00
0x00702dfdfe10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Thread T2 created by T0 here:
#0 0x100ae8c5c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x38c5c)
#1 0x10010a360 in google_breakpad::ExceptionHandler::Setup(bool)+0xd0 (my_server:arm64+0x10010a360)
#2 0x10010a1c4 in google_breakpad::ExceptionHandler::ExceptionHandler(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool (*)(void*), bool (*)(char const*, char const*, void*, bool), void*, bool, char const*)+0x110 (my_server:arm64+0x10010a1c4)
#3 0x1001132b4 in crashhandler::init(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+0x58 (my_server:arm64+0x1001132b4)
#4 0x10000367c in main main.cpp:41
#5 0x1a2fdfe4c (<unknown module>)
==5060==ABORTING
To reiterate, if I run the program outside of the debugger, it proceeds normally.
What can cause this?
Breakpad is inserting a right into the process's "task exception port" - which is where you listen for crashes and the like either from within the process or externally - i.e. when you are a debugger. But in Mach the exception ports only have a single owner. So when you run under the debugger, Breakpad and the debugger fight for control of the exception port. For example, if you got your port right set up before the debugger attached, you will end up with a bad port right after the attach, because lldb now owns the port.
Debugging programs that use task exception port handlers is not well supported, because (a) it would be tricky to get that right and (b) there aren't enough programs that need to do this to motivate the effort (at least on the debugger side). Most people turn off their exception handling for their debug builds since their exception catcher and the debugger are pretty much doing the same job, and it's more convenient to trap in the debugger than the internal exception handler. And the core part of the exception handler is usually simple enough that you can do printf debugging if you really need to debug that part.

c++ boost base64 decoder fails when newlines are present

when given base64 'text' to decode, that contains new lines, the following will throw an exception - non base64 characters present. In reference to the new lines.
terminate called after throwing an instance of 'boost::archive::iterators::dataflow_exception'
what(): attempt to decode a value not in base64 char set
Does anyone know how to tell boost to gracefully handle newlines? I recognize I could remove them myself from the string, prior to decoding, but was hoping and guessing there was a more streamlined way.
typedef transform_width< binary_from_base64<remove_whitespace<char*>>, 8, 6 > base64_dec;
unsigned int size = s.size(); //where 's' is the string holding the base64 characters to include newlines at every 76th character
std::string decoded_token(base64_dec(s.c_str()), base64_dec(s.c_str() + size));
Okay, so the trouble is that newlines are not the problem. The filter_iterator is just fundamentally broken.
It will cause Undefined Behaviour as soon as the input sequence ends in a character that doesn't satisfy the filter predicate (in this case, a whitespace character):
Crashing Live On Compiler Explorer
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <iomanip>
#include <iostream>
namespace bai = boost::archive::iterators;
int main() {
using It = bai::remove_whitespace<const char*>;
std::string const s = "oops "; // ends in whitespace, causes UB
std::string filtered(It(s.c_str()), It(s.c_str() + s.length()));
std::cout << std::quoted(filtered) << std::flush;
}
Prints, with ASan enabled (without it it just segfaults):
=================================================================
==1==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffecf132b0 at pc 0x00000040390d bp 0x7fffecf12fd0 sp 0x7fffecf12fc8
READ of size 1 at 0x7fffecf132b0 thread T0
#0 0x40390c in dereference_impl /opt/compiler-explorer/libs/boost_1_78_0/boost/archive/iterators/remove_whitespace.hpp:105
#1 0x40390c in dereference /opt/compiler-explorer/libs/boost_1_78_0/boost/archive/iterators/remove_whitespace.hpp:113
#2 0x40390c in dereference<boost::archive::iterators::filter_iterator<(anonymous namespace)::remove_whitespace_predicate<char>, char const*> > /opt/compiler-explorer/libs/boost_1_78_0/boost/iterator/iterator_facade.hpp:550
#3 0x40390c in operator* /opt/compiler-explorer/libs/boost_1_78_0/boost/iterator/iterator_facade.hpp:656
#4 0x40390c in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<boost::archive::iterators::remove_whitespace<char const*> >(boost::archive::iterators::remove_whitespace<char const*>, boost::archive::iterators::remove_whitespace<char const*>, std::input_iterator_tag) /opt/compiler-explorer/gcc-trunk-20220419/include/c++/12.0.1/bits/basic_string.tcc:204
#5 0x40390c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<boost::archive::iterators::remove_whitespace<char const*>, void>(boost::archive::iterators::remove_whitespace<char const*>, boost::archive::iterators::remove_whitespace<char const*>, std::allocator<char> const&) /opt/compiler-explorer/gcc-trunk-20220419/include/c++/12.0.1/bits/basic_string.h:756
#6 0x40390c in main /app/example.cpp:11
#7 0x7fb625b560b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x240b2)
#8 0x4041ed in _start (/app/output.s+0x4041ed)
Address 0x7fffecf132b0 is located in stack of thread T0 at offset 576 in frame
#0 0x40245f in main /app/example.cpp:7
This frame has 21 object(s):
[32, 33) '<unknown>'
[48, 49) '<unknown>'
[64, 65) '<unknown>'
[80, 81) '<unknown>'
[96, 97) '<unknown>'
[112, 113) '<unknown>'
[128, 136) 'start'
[160, 168) 'start'
[192, 200) '__guard'
[224, 232) 'start'
[256, 264) 'start'
[288, 296) '__capacity'
[320, 328) '__guard'
[352, 368) '<unknown>'
[384, 400) '<unknown>'
[416, 432) '<unknown>'
[448, 464) '<unknown>'
[480, 496) '<unknown>'
[512, 528) '<unknown>'
[544, 576) 's' (line 9) <== Memory access at offset 576 overflows this variable
[608, 640) 'filtered' (line 11)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /opt/compiler-explorer/libs/boost_1_78_0/boost/archive/iterators/remove_whitespace.hpp:105 in dereference_impl
Shadow bytes around the buggy address:
0x10007d9da600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x10007d9da610: f1 f1 f8 f2 01 f2 f8 f2 f8 f2 f8 f2 01 f2 00 f2
0x10007d9da620: f2 f2 00 f2 f2 f2 f8 f2 f2 f2 00 f2 f2 f2 00 f2
0x10007d9da630: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 00 f2 f2 00 00
0x10007d9da640: f2 f2 00 00 f2 f2 00 00 f2 f2 00 00 f2 f2 00 00
=>0x10007d9da650: f2 f2 00 00 00 00[f2]f2 f2 f2 00 00 00 00 f3 f3
0x10007d9da660: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007d9da670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007d9da680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007d9da690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007d9da6a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1==ABORTING
You can consider yourself lucky that you noticed due to symptoms, instead of it eating your puppy or launching the nukes in production code.
This should be reported. There is no test for filter_iterator (or even remove_whitespace for that matter) in isolation, and previous tickets seem to indicate a stance like "It Works For Me" (where "Me" is the Boost Serialization Library). See e.g. https://github.com/boostorg/serialization/issues/135.
Interestingly the analysis at that ticket makes zero sense, since there hasn't been a two-iterator constructor for filter_iterator since ... forever. I can only guess that Robert mistakenly looked at Boost Iterator instead of the filter_iterator from Boost Archive.
So my hunch was to recommend you use filter_iterator.hpp from Boost Iterator
instead. Ironically it took several tries (and a trip to cppslack/github) to
get right, but here it is: Live On Compiler Explorer
Fix Using Boost Iterator's filter_iterator
We should be able to fix using the working filter_iterator implementation:
using FiltIt =
boost::iterators::filter_iterator<IsGraph, std::string::const_iterator>;
using base64_dec = //
bai::transform_width< //
bai::binary_from_base64<FiltIt>, 8, 6>; //
Now, it's still tricky to get it right. Notably, the naive approach will just fail with UB again:
// CAUTION: this invokes UB:
std::string filtered(base64_dec(s.begin()), base64_dec(s.end()));
It's the curse of implicit conversions + default arguments. Instead we MUST explicitly construct the FiltIt separately:
FiltIt f(IsGraph{}, s.begin(), s.end()), // !!
l(f.predicate(), f.end(), f.end()); // !!
Now we can "just" use them in base64_dec:
std::string filtered(base64_dec{f}, base64_dec{l});
Note the uniform {} initializers to sidestep Most Vexing Parse
Live On Compiler Explorer
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <iomanip>
#include <iostream>
namespace bai = boost::archive::iterators;
static std::string const s = "aGVsbG8g\nd29ybGQK";
int main() {
std::cout << std::unitbuf;
struct IsGraph {
// unsigned char prevents sign extension
bool operator()(unsigned char ch) const {
return std::isgraph(ch); // !std::isspace
}
};
using FiltIt =
boost::iterators::filter_iterator<IsGraph, std::string::const_iterator>;
using base64_dec = //
bai::transform_width< //
bai::binary_from_base64<FiltIt>, 8, 6>; //
//// CAUTION: this invokes UB:
//std::string filtered(base64_dec(s.begin()), base64_dec(s.end()));
FiltIt f(IsGraph{}, s.begin(), s.end()), // !!
l(f.predicate(), f.end(), f.end()); // !!
std::string filtered(base64_dec{f}, base64_dec{l});
std::cout << "OUT:" << std::quoted(filtered) << std::endl;
}
Prints itself (minus the sample base64)
OUT:"hello world
"
Summary/TL;DR
Consider the lurking bugs and undocumented limitations, consider using a
proper, simpler base64 implementation.
Beast has one in its implementation details, so that's also unsupported, but
chances are pretty high that it is at least less brittle.
Alternatively the must be a library that has proper tests and documentation.

Populating map with new pointers in a loop (C++)

So I am working on the Copy List with Random Pointer question from leetcode and ran into a bit of a problem.
for (; iterateOG->next != nullptr;
iterateOG = iterateOG->next) {
Node* tmp = new Node;
hashTable.insert(std::pair<Node*,Node*>(iterateOG,tmp));
}
So I want to create a new Node object for every existing node in the orginal list. After running the test cases I get an error message like including the HINT below
'hashTable' <== Memory access at offset 912 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Does anyone know what is causing this problem? I know the cause might be because I created a new object and didn't do anything with it within the scope, but I don't see a solution around this problem. Any help would be appreciated. Thank you!
Full code and error message below
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node() {}
Node(int _val, Node* _next, Node* _random) {
val = _val;
next = _next;
random = _random;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
if (head == nullptr)
return nullptr;
Node* iterateOG = head;
std::map<Node*, Node*> hashTable;
for (; iterateOG->next != nullptr;
iterateOG = iterateOG->next) {
Node* tmp = new Node;
hashTable.insert(std::pair<Node*,Node*>(iterateOG,tmp));
}
std::cout << endl;
iterateOG = head;
for (; iterateOG->next != nullptr;
iterateOG = iterateOG->next) {
hashTable.find(iterateOG)->second->val = iterateOG->val;
hashTable.find(iterateOG)->second->next = hashTable.find(iterateOG->next)->second;
hashTable.find(iterateOG)->second->random = hashTable.find(iterateOG->random)->second;
std::cout << hashTable.find(iterateOG)->second->val << ',';
}
std::cout << endl;
return hashTable.find(head)->second;
}
};
Error Message
=================================================================
==29==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc4dbbbb70 at pc 0x00000041d7eb bp 0x7ffc4dbbb7b0 sp 0x7ffc4dbbb7a8
READ of size 8 at 0x7ffc4dbbbb70 thread T0
#2 0x7fa042ca92e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0)
Address 0x7ffc4dbbbb70 is located in stack of thread T0 at offset 912 in frame
This frame has 14 object(s):
[32, 33) '__c'
[96, 97) '__c'
[160, 168) 'iterateOG'
[224, 232) 'tmp'
[288, 296) '<unknown>'
[352, 360) '<unknown>'
[416, 424) '<unknown>'
[480, 488) '<unknown>'
[544, 552) '<unknown>'
[608, 616) '<unknown>'
[672, 680) '<unknown>'
[736, 744) 'head'
[800, 816) '<unknown>'
[864, 912) 'hashTable' <== Memory access at offset 912 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x100009b6f710: 00 f2 f2 f2 f2 f2 f2 f2 f8 f2 f2 f2 f2 f2 f2 f2
0x100009b6f720: f8 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 f2 f2
0x100009b6f730: 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 f2 f2
0x100009b6f740: 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 f2 f2
0x100009b6f750: 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 f2 f2
=>0x100009b6f760: f8 f8 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00[f2]f2
0x100009b6f770: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x100009b6f780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009b6f790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009b6f7a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009b6f7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==29==ABORTING
The bug is on this line:
hashTable.find(iterateOG)->second->next = hashTable.find(iterateOG->next)->second;
For the last node iterateOG->next has value that isn't in hashTable.

std::bind and stack-use-after-scope

So, today I was running some code built with Address Sanitizer and have stumbled upon a strange stack-use-after-scope bug.
I have this simplified example:
#include <functional>
class k
{
public: operator int(){return 5;}
};
const int& n(const int& a)
{
return a;
}
int main()
{
k l;
return std::bind(n, l)();
}
ASAN complains about the last code line:
==27575==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffeab375210 at pc 0x000000400a01 bp 0x7ffeab3750e0 sp 0x7ffeab3750d8
READ of size 4 at 0x7ffeab375210 thread T0
#0 0x400a00 (/root/tstb.exe+0x400a00)
#1 0x7f97ce699730 in __libc_start_main (/lib64/libc.so.6+0x20730)
#2 0x400a99 (/root/tstb.exe+0x400a99)
Address 0x7ffeab375210 is located in stack of thread T0 at offset 288 in frame
#0 0x40080f (/root/tstb.exe+0x40080f)
This frame has 6 object(s):
[32, 33) '<unknown>'
[96, 97) '<unknown>'
[160, 161) '<unknown>'
[224, 225) '<unknown>'
[288, 292) '<unknown>' <== Memory access at offset 288 is inside this variable
[352, 368) '<unknown>'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope (/root/tstb.exe+0x400a00)
Shadow bytes around the buggy address:
0x1000556669f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x100055666a20: f1 f1 f8 f2 f2 f2 f2 f2 f2 f2 f8 f2 f2 f2 f2 f2
0x100055666a30: f2 f2 f8 f2 f2 f2 f2 f2 f2 f2 f8 f2 f2 f2 f2 f2
=>0x100055666a40: f2 f2[f8]f2 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f3 f3
0x100055666a50: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100055666a90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==27575==ABORTING
If I understand correctly, it says that we are accessing a stack variable after it has already gone out of scope.
Looking at the uninstrumented and unoptimized disassembly I indeed see that it happens inside instantiated __invoke_impl :
Dump of assembler code for function std::__invoke_impl<int const&, int const& (*&)(int const&), k&>(std::__invoke_other, int const& (*&)(int const&), k&):
0x0000000000400847 <+0>: push %rbp
0x0000000000400848 <+1>: mov %rsp,%rbp
0x000000000040084b <+4>: push %rbx
0x000000000040084c <+5>: sub $0x28,%rsp
0x0000000000400850 <+9>: mov %rdi,-0x28(%rbp)
0x0000000000400854 <+13>: mov %rsi,-0x30(%rbp)
0x0000000000400858 <+17>: mov -0x28(%rbp),%rax
0x000000000040085c <+21>: mov %rax,%rdi
0x000000000040085f <+24>: callq 0x4007a2 <std::forward<int const& (*&)(int const&)>(std::remove_reference<int const& (*&)(int const&)>::type&)>
0x0000000000400864 <+29>: mov (%rax),%rbx
0x0000000000400867 <+32>: mov -0x30(%rbp),%rax
0x000000000040086b <+36>: mov %rax,%rdi
0x000000000040086e <+39>: callq 0x4005c4 <std::forward<k&>(std::remove_reference<k&>::type&)>
0x0000000000400873 <+44>: mov %rax,%rdi
0x0000000000400876 <+47>: callq 0x40056a <k::operator int()>
0x000000000040087b <+52>: mov %eax,-0x14(%rbp)
0x000000000040087e <+55>: lea -0x14(%rbp),%rax
0x0000000000400882 <+59>: mov %rax,%rdi
0x0000000000400885 <+62>: callq *%rbx
=> 0x0000000000400887 <+64>: add $0x28,%rsp
0x000000000040088b <+68>: pop %rbx
0x000000000040088c <+69>: pop %rbp
0x000000000040088d <+70>: retq
End of assembler dump.
After calling k::operator int() it places the returned value on the stack and passes its address to the n(), which immediately returns it, and then it is returned from __invoke_impl itself (and goes all the way up to main's return).
So, it looks like ASAN it right here and we really have an stack-use-after-scope access.
The question is: What is wrong with my code?
I have tried building it with gcc, clang and icc and they all produce similar assembler outputs.
std::bind essentially generates an implementation function object that calls the bound function with the desired arguments. In your case, this implementation function object is about equivalent to
struct Impl
{
const int &operator()() const
{
int tmp = k_;
return n(tmp);
}
private:
k k_;
Impl(/*unspecified*/);
};
Since n returns its argument as a const reference, the call operator of Impl will return a reference to a local variable, which is a dangling reference, which is then read from in main. Hence the stack use after scope error.
Your confusion may stem from the fact that return n(l); without the bind is expected to work fine here. However, in the latter case, the temporary int is created in the stack frame of main, lives for the duration of the full expression that makes up the argument to return, which is evaluated to int.
In other words, while a temporary lives until the end of the full expression in which it was created, this is not the case for temporaries generated inside functions called within that full expression. These are considered part of a different full expression and are destroyed when that expression has been evaluated.
PS: For this reason, binding any function (object) of signature R(Args...) to a std::function<const R&(Args...)> results in a guaranteed return of a dangling reference when called – a construct that IMO the library should reject at compile time.
Ok this is a tough one if you don't know the specifics about std::bind.
When binding an argument to a callable with std::bind, a copy of the argument is maid (source):
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
std::bind(n, l) returns a callable object of unspecified type having a member object of type k build as a copy of l. Please note this callable object is a temporary (an rvalue) I'll give it a name: bindtmp.
When invoked, bindtmp() creates a temporary (inttemp) integer (5) in order to apply bindtmp::lcopy to bindtmp::ncopy (those are the member objects constructed from main::l and ::n). ::n returns a const reference to inttemp inside the scope of bindtmp() in a return statement.
This is where things get tricky (source):
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
- a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
- ...
This means, the temporary inttemp is destroyed after ::n has returned.
From this point, everything falls apart. bindtmp() returns a reference to an object whose lifetime has ended, main tries and convert it into an lvalue, and thi sis where undefined behaviour (odr-use of an object from the stack after its use) happens.

client server simple example nonblocking

In this code, the server is not accepting any more client but only one.
Say one client has been accepted and after the server got a message and sent "HELLO" to the client, the server is not accepting another client, why?
#include <boost\asio.hpp>
#include <boost\bind.hpp>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
void accept_handle(const boost::system::error_code& eCode, boost::asio::ip::tcp::socket* client, boost::asio::ip::tcp::acceptor* server);
void read_handle(const boost::system::error_code& eCode, std::size_t bytes, boost::asio::ip::tcp::socket* client, boost::asio::ip::tcp::acceptor* server);
void write_handle(const boost::system::error_code& eCode, std::size_t bytes, boost::asio::ip::tcp::acceptor* server);
int main(int argc, char** argv)
{
boost::asio::io_service service;
boost::asio::ip::tcp::acceptor server(service);
boost::system::error_code eCode;
boost::asio::ip::tcp::endpoint point(boost::asio::ip::address::from_string("127.0.0.1"), 12345);
server.open(point.protocol());
server.bind(point);
server.listen(987);
boost::asio::ip::tcp::socket connection(service);
server.async_accept(connection, boost::bind(accept_handle, _1, &connection, &server));
service.run();
system("pause");
return 0;
}
void write_handle(const boost::system::error_code& eCode, std::size_t bytes, boost::asio::ip::tcp::acceptor* server)
{
if (!eCode)
{
cout << "Written" << endl;
cout << "Done" << endl;
boost::asio::ip::tcp::socket connection(server->get_io_service());
server->async_accept(connection, boost::bind(accept_handle, _1, &connection, server));
}
else {
cout << "NOT written" << endl;
}
}
void read_handle(const boost::system::error_code& eCode, std::size_t bytes, boost::asio::ip::tcp::socket* client, boost::asio::ip::tcp::acceptor* server)
{
if (!eCode)
{
cout << "Read" << endl;
client->async_write_some(boost::asio::buffer("HELLO"), boost::bind(write_handle, _1, _2, server));
}else{
cout << "NOT read" << endl;
}
}
void accept_handle(const boost::system::error_code& eCode, boost::asio::ip::tcp::socket* client, boost::asio::ip::tcp::acceptor* server)
{
if (!eCode)
{
char data[6];
cout << "Connected" << endl;
client->async_read_some(boost::asio::buffer(data, 6), boost::bind(read_handle, _1, _2, client, server));
cout << data << endl;
}
else {
cout << "NOT connected" << endl;
}
}
NOTE-> I did a function which first gets the size of the message coming from a client so that the server can allocate enough memory and after that gets the message itself, so the second problem is how can i use my function in async_read_some / async_write_some??? i think this idea getting first the size of the message and then the message itself using s is not very good, have got another ideas for it???
First, make sure you handle and show errors:
std::cout << "NOT written: " << eCode.message() << "\n";
// ...
std::cout << "NOT read: " << eCode.message() << "\n";
// ...
std::cout << "NOT connected: " << eCode.message() << "\n";
Next, enable Asan/UBSan! -fsanitze=undefined,address gives this on the first connection already:
=================================================================
==409==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc048aa8d6 at pc 0x7f82f079043e bp 0x7ffc048aa790 sp 0x7ffc048a9f38
READ of size 7 at 0x7ffc048aa8d6 thread T0
#0 0x7f82f079043d (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5143d)
#1 0x7f82f02c7398 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x114398)
#2 0x405338 in accept_handle(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*) /home/sehe/Projects/stackoverflow/test.cpp:58
#3 0x444789 in void boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> >::operator()<void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::rrlist1<boost::system::error_code const&> >(boost::_bi::type<void>, void (*&)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::rrlist1<boost::system::error_code const&>&, int) (/home/sehe/Projects/stackoverflow/sotest+0x444789)
#4 0x443d14 in void boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >::operator()<boost::system::error_code const&>(boost::system::error_code const&) (/home/sehe/Projects/stackoverflow/sotest+0x443d14)
#5 0x4439ab in boost::asio::detail::binder1<boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >, boost::system::error_code>::operator()() (/home/sehe/Projects/stackoverflow/sotest+0x4439ab)
#6 0x442f19 in void boost::asio::asio_handler_invoke<boost::asio::detail::binder1<boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >, boost::system::error_code> >(boost::asio::detail::binder1<boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >, boost::system::error_code>&, ...) (/home/sehe/Projects/stackoverflow/sotest+0x442f19)
#7 0x441532 in void boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder1<boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >, boost::system::error_code>, boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > > >(boost::asio::detail::binder1<boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >, boost::system::error_code>&, boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > >&) (/home/sehe/Projects/stackoverflow/sotest+0x441532)
#8 0x43f64b in boost::asio::detail::reactive_socket_accept_op<boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ip::tcp, boost::_bi::bind_t<void, void (*)(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*), boost::_bi::list3<boost::arg<1>, boost::_bi::value<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*>, boost::_bi::value<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*> > > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x43f64b)
#9 0x41326f in boost::asio::detail::task_io_service_operation::complete(boost::asio::detail::task_io_service&, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x41326f)
#10 0x41fe4b in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x41fe4b)
#11 0x41326f in boost::asio::detail::task_io_service_operation::complete(boost::asio::detail::task_io_service&, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x41326f)
#12 0x42463d in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) (/home/sehe/Projects/stackoverflow/sotest+0x42463d)
#13 0x42286c in boost::asio::detail::task_io_service::run(boost::system::error_code&) (/home/sehe/Projects/stackoverflow/sotest+0x42286c)
#14 0x425aba in boost::asio::io_service::run() (/home/sehe/Projects/stackoverflow/sotest+0x425aba)
#15 0x40465d in main /home/sehe/Projects/stackoverflow/test.cpp:28
#16 0x7f82eecb682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#17 0x404178 in _start (/home/sehe/Projects/stackoverflow/sotest+0x404178)
Address 0x7ffc048aa8d6 is located in stack of thread T0 at offset 230 in frame
#0 0x405082 in accept_handle(boost::system::error_code, boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >*, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> >*) /home/sehe/Projects/stackoverflow/test.cpp:52
This frame has 4 object(s):
[32, 48) '<unknown>'
[96, 120) '<unknown>'
[160, 192) '<unknown>'
[224, 230) 'data' <== Memory access at offset 230 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5143d)
Shadow bytes around the buggy address:
0x10000090d4c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000090d4d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000090d4e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000090d4f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x10000090d500: f1 f1 f8 f8 f2 f2 f2 f2 f2 f2 f8 f8 f8 f2 f2 f2
=>0x10000090d510: f2 f2 00 00 00 00 f2 f2 f2 f2[06]f2 f2 f2 00 00
0x10000090d520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000090d530: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 01 f2
0x10000090d540: f2 f2 f2 f2 f2 f2 00 f2 f2 f2 00 00 00 00 00 00
0x10000090d550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000090d560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==409==ABORTING
Cause:
In your handle_accept you have
std::cout << data << "\n";
This prints data but there is no zero-termination. Adding it:
char data[7] = {0};
leads to the next violation:
=================================================================
==2055==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffe09a1c640 at pc 0x7f45551cb739 bp 0x7ffe09a1bd20 sp 0x7ffe09a1b4c8
WRITE of size 6 at 0x7ffe09a1c640 thread T0
#0 0x7f45551cb738 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x3a738)
#1 0x7f455522e305 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9d305)
#2 0x7f455522ef43 in __interceptor_recvmsg (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x9df43)
#3 0x42828d in boost::asio::detail::socket_ops::recv(int, iovec*, unsigned long, int, boost::system::error_code&) (/home/sehe/Projects/stackoverflow/sotest+0x42828d)
#4 0x428554 in boost::asio::detail::socket_ops::non_blocking_recv(int, iovec*, unsigned long, int, bool, boost::system::error_code&, unsigned long&) (/home/sehe/Projects/stackoverflow/sotest+0x428554)
#5 0x442938 in boost::asio::detail::reactive_socket_recv_op_base<boost::asio::mutable_buffers_1>::do_perform(boost::asio::detail::reactor_op*) (/home/sehe/Projects/stackoverflow/sotest+0x442938)
#6 0x4138b4 in boost::asio::detail::reactor_op::perform() (/home/sehe/Projects/stackoverflow/sotest+0x4138b4)
#7 0x41fbe6 in boost::asio::detail::epoll_reactor::descriptor_state::perform_io(unsigned int) (/home/sehe/Projects/stackoverflow/sotest+0x41fbe6)
#8 0x41fe55 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x41fe55)
#9 0x4132e3 in boost::asio::detail::task_io_service_operation::complete(boost::asio::detail::task_io_service&, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x4132e3)
#10 0x4246b1 in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) (/home/sehe/Projects/stackoverflow/sotest+0x4246b1)
#11 0x4228e0 in boost::asio::detail::task_io_service::run(boost::system::error_code&) (/home/sehe/Projects/stackoverflow/sotest+0x4228e0)
#12 0x425b2e in boost::asio::io_service::run() (/home/sehe/Projects/stackoverflow/sotest+0x425b2e)
#13 0x40465d in main /home/sehe/Projects/stackoverflow/test.cpp:28
#14 0x7f455370882f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#15 0x404178 in _start (/home/sehe/Projects/stackoverflow/sotest+0x404178)
Address 0x7ffe09a1c640 is located in stack of thread T0 at offset 16 in frame
#0 0x647361647370 (<unknown module>)
This frame has 2 object(s):
[32, 48) '<unknown>' <== Memory access at offset 16 underflows this variable
[96, 152) 'msg'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x3a738)
Shadow bytes around the buggy address:
0x10004133b870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004133b880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004133b890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004133b8a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004133b8b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10004133b8c0: 00 00 00 00 00 00 f1 f1[f1]f1 00 00 f2 f2 f2 f2
0x10004133b8d0: f2 f2 00 00 00 00 00 00 00 f2 00 00 00 00 00 00
0x10004133b8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x10004133b8f0: f1 f1 00 00 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f2 f2
0x10004133b900: f2 f2 00 00 f2 f2 f2 f2 f2 f2 00 00 f2 f2 00 00
0x10004133b910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==2055==ABORTING
This is caused by the fact that:
char data[7] = {0};
std::cout << "Connected\n";
client->async_read_some(ba::buffer(data, 6), boost::bind(read_handle, _1, _2, client, server));
Passes ba::buffer(data, 6) to an asynchronous operation, but the asynchronous operation doesn't complete before accept_handle returns, so data doesn't exist anymore. OOPS.
You can of course make it a global variable, but that means you cannot have more than one connection. For now, let's do this (we'll fix it later):
static char data[7]; // TODO FIXME global data shared across connections
void accept_handle(error_code eCode, tcp::socket *client, tcp::acceptor *server) {
if (!eCode) {
std::fill_n(data, sizeof(data), '\0');
std::cout << "Connected\n";
client->async_read_some(ba::buffer(data, 6), boost::bind(read_handle, _1, _2, client, server));
std::cout << data << "\n";
} else {
std::cout << "NOT connected: " << eCode.message() << "\n";
}
}
Now at least the first connection "succeeds". Next connection, BOOM:
/home/sehe/custom/boost_1_65_0/boost/asio/basic_io_object.hpp:225:13: runtime error: reference binding to misaligned address 0x000000000012 for type 'struct service_type', which requires 8 byte alignment
0x000000000012: note: pointer points here
<memory cannot be printed>
/home/sehe/custom/boost_1_65_0/boost/asio/basic_socket.hpp:331:36: runtime error: member call on misaligned address 0x000000000012 for type 'struct service_type', which requires 8 byte alignment
0x000000000012: note: pointer points here
<memory cannot be printed>
/home/sehe/custom/boost_1_65_0/boost/asio/basic_socket.hpp:331:36: runtime error: member access within misaligned address 0x000000000012 for type 'struct service_type', which requires 8 byte alignment
0x000000000012: note: pointer points here
<memory cannot be printed>
ASAN:DEADLYSIGNAL
=================================================================
==5056==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000012 (pc 0x000000443294 bp 0x7fffc08266d0 sp 0x7fffc08266a0 T0)
==5056==The signal is caused by a READ memory access.
==5056==Hint: address points to the zero page.
#0 0x443293 in boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >::assign(boost::asio::ip::tcp const&, int const&, boost::system::error_code&) (/home/sehe/Projects/stackoverflow/sotest+0x443293)
#1 0x441e20 in boost::asio::detail::reactive_socket_accept_op_base<boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ip::tcp>::do_perform(boost::asio::detail::reactor_op*) (/home/sehe/Projects/stackoverflow/sotest+0x441e20)
#2 0x4138f6 in boost::asio::detail::reactor_op::perform() (/home/sehe/Projects/stackoverflow/sotest+0x4138f6)
#3 0x41fc28 in boost::asio::detail::epoll_reactor::descriptor_state::perform_io(unsigned int) (/home/sehe/Projects/stackoverflow/sotest+0x41fc28)
#4 0x41fe97 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x41fe97)
#5 0x413325 in boost::asio::detail::task_io_service_operation::complete(boost::asio::detail::task_io_service&, boost::system::error_code const&, unsigned long) (/home/sehe/Projects/stackoverflow/sotest+0x413325)
#6 0x4246f3 in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) (/home/sehe/Projects/stackoverflow/sotest+0x4246f3)
#7 0x422922 in boost::asio::detail::task_io_service::run(boost::system::error_code&) (/home/sehe/Projects/stackoverflow/sotest+0x422922)
#8 0x425b70 in boost::asio::io_service::run() (/home/sehe/Projects/stackoverflow/sotest+0x425b70)
#9 0x40465d in main /home/sehe/Projects/stackoverflow/test.cpp:28
#10 0x7f33164b182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#11 0x404178 in _start (/home/sehe/Projects/stackoverflow/sotest+0x404178)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/sehe/Projects/stackoverflow/sotest+0x443293) in boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >::assign(boost::asio::ip::tcp const&, int const&, boost::system::error_code&)
==5056==ABORTING
The problem is similar:
tcp::socket connection(server->get_io_service());
server->async_accept(connection, boost::bind(accept_handle, _1, &connection, server));
You're passing a local variable into async_accept again. Applying a similar fix:
void do_accept(tcp::acceptor& server) {
static tcp::socket connection(server.get_io_service()); // TODO FIXME global data shared
if (connection.is_open())
connection.close();
server.async_accept(connection, boost::bind(accept_handle, _1, &connection, &server));
}
Now your server can accept several connections in succession:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
namespace ba = boost::asio;
using ba::ip::tcp;
using boost::system::error_code;
void accept_handle(error_code eCode, tcp::socket *client, tcp::acceptor *server);
void read_handle(error_code eCode, std::size_t bytes, tcp::socket *client, tcp::acceptor *server);
void write_handle(error_code eCode, std::size_t bytes, tcp::acceptor *server);
void do_accept(tcp::acceptor& a);
int main() {
ba::io_service service;
tcp::acceptor server(service);
tcp::endpoint endpoint{{}, 12345};
server.open(endpoint.protocol());
server.set_option(tcp::acceptor::reuse_address(true));
server.bind(endpoint);
server.listen();
do_accept(server);
service.run();
}
void do_accept(tcp::acceptor& server) {
static tcp::socket connection(server.get_io_service()); // TODO FIXME global data shared
if (connection.is_open())
connection.close();
server.async_accept(connection, boost::bind(accept_handle, _1, &connection, &server));
}
static char data[7]; // TODO FIXME global data shared across connections
void accept_handle(error_code eCode, tcp::socket *client, tcp::acceptor *server) {
if (!eCode) {
std::fill_n(data, sizeof(data), '\0');
std::cout << "Connected\n";
client->async_read_some(ba::buffer(data, 6), boost::bind(read_handle, _1, _2, client, server));
std::cout << data << "\n";
} else {
std::cout << "NOT connected: " << eCode.message() << "\n";
}
}
void read_handle(error_code eCode, std::size_t bytes, tcp::socket *client, tcp::acceptor *server) {
if (!eCode) {
std::cout << "Read\n";
client->async_write_some(ba::buffer("HELLO\n"), boost::bind(write_handle, _1, _2, server));
} else {
std::cout << "NOT read: " << eCode.message() << "\n";
}
}
void write_handle(error_code eCode, std::size_t bytes, tcp::acceptor *server) {
if (!eCode) {
std::cout << "Written\n";
std::cout << "Done\n";
do_accept(*server);
} else {
std::cout << "NOT written: " << eCode.message() << "\n";
}
}