Opened 5 years ago
Last modified 4 years ago
#13515 new Bugs
async_pipe::async_read_some returns zero read size if -O<something> is used
Reported by: | Owned by: | chris_kohlhoff | |
---|---|---|---|
Milestone: | To Be Determined | Component: | asio |
Version: | Boost 1.66.0 | Severity: | Problem |
Keywords: | Cc: |
Description
Hi there,
We are developing coroutine based application which sits mostly on some sort of I/O. Decided to go with coroutine based approach with boost 1.66 and asio/beast/process libs. While doing some internal POC we ran into issue with retrieving size of data obtained through pipe.
#include <boost/asio.hpp> #include <boost/asio/spawn.hpp> #include <boost/process.hpp> #include <chrono> #include <iostream> void test_process() { static const char* path = "./dataspit.py"; static const char* interpreter = "python3"; std::cout << "Hello from streamer2\n"; namespace asio = boost::asio; namespace process = boost::process; namespace chrono = std::chrono; asio::io_context ioc; asio::spawn(ioc, [&ioc](asio::yield_context yield) { process::async_pipe pipe{ioc}; auto child = process::child{process::search_path(interpreter), path, process::std_out > pipe}; std::array<char, 4096> buffer{0}; std::cout << "Buffer state: " << (int)buffer[0] << (int)buffer[1] << std::endl; boost::system::error_code read_ec; do { auto timePoint = chrono::system_clock::now(); std::cout << timePoint.time_since_epoch().count() << ": Sleeping\n"; std::size_t size = pipe.async_read_some(asio::buffer(buffer), yield[read_ec]); if (read_ec) { std::cerr << read_ec.message() << std::endl; break; } timePoint = chrono::system_clock::now(); std::cout << timePoint.time_since_epoch().count() << ": Read " << size << " bytes\n"; std::cout << "Buffer state: " << (int)buffer[0] << (int)buffer[1] << std::endl; } while (read_ec != boost::asio::error::eof); child.wait(); } ); ioc.run(); std::cout << "Farewell from streamer2\n"; } int main(int argc, char** argv) { test_process(); return 0; }
This code works fine when no compiler optimizations are used. As soon as its compiled with -Os or any numbered -O type.
pipe.async_read_some(asio::buffer(buffer), yield[read_ec]);
starts returning 0. Buffer contents are modified though. Callback based approach yields same result.
... readv(6, [{"57757488835088650590974423544437"..., 4096}], 1) = 1030 write(1, "1523018074402113597: Read 0 byte"..., 341523018074402113597: Read 0 bytes) = 34 write(1, "Buffer state: 5355\n", 19Buffer state: 5355) = 19 write(1, "1523018074402457408: Sleeping\n", 301523018074402457408: Sleeping) = 30 readv(6, 0x83c2168, 1) = -1 EAGAIN (Resource temporarily unavailable) epoll_wait(4, [{EPOLLIN, {u32=138163408, u64=138163408}}], 128, -1) = 1 readv(6, [{"15827357453760420053575823774839"..., 4096}], 1) = 546 write(1, "1523018076807802498: Read 0 byte"..., 341523018076807802498: Read 0 bytes) = 34 write(1, "Buffer state: 4953\n", 19Buffer state: 4953) = 19 write(1, "1523018076808233410: Sleeping\n", 301523018076808233410: Sleeping) = 30 readv(6, 0x83c2168, 1) = -1 EAGAIN (Resource temporarily unavailable) epoll_wait(4, [{EPOLLIN, {u32=138163408, u64=138163408}}], 128, -1) = 1 readv(6, [{"66365484273136085944223051047033"..., 4096}], 1) = 814 write(1, "1523018079517434883: Read 0 byte"..., 341523018079517434883: Read 0 bytes) = 34 write(1, "Buffer state: 5454\n", 19Buffer state: 5454) = 19 write(1, "1523018079517782099: Sleeping\n", 301523018079517782099: Sleeping) = 30 readv(6, 0x83c2168, 1) = -1 EAGAIN (Resource temporarily unavailable) ...
Epoll waits as expected, readv seems to return length as well. Looks like some kind of reordering issue.
Tested this behavior on ubuntu 14.04/16.04 in 32/64bit modes on using stock gcc, all ran in docker containers within ubuntu 16.04 host.
Issue applies to boost 1.66 for sure, tested also 1.65 and 1.67 beta on ubuntu 14.04 32 bit. Issue is there as well.
Complete sample code in attachments.
I'd be grateful for some notification if you find root cause and possible patch. I'd like to apply such to our boost sources.
Best Regards, Tomasz Jonak
Attachments (1)
Change History (3)
by , 5 years ago
Attachment: | asio_bug_sample.tar.bz2 added |
---|
comment:1 by , 4 years ago
comment:2 by , 4 years ago
error::eof is an enum value of type boost::asio::error::errc; in this context read_ec will be converted to bool and compared against the integer value of error::eof.
Apparently this not the case. I tested in gdb and boost::asio::error::eof is first converted to an error_code which is then compared to read_ec.
Hello,
error::eof is an enum value of type boost::asio::error::errc; in this context read_ec will be converted to bool and compared against the integer value of error::eof.
Try to compare against
read_ec.value()
instead.