Ticket #3627 (new Feature Requests)

Opened 7 years ago

Last modified 7 years ago

boost::asio::async_read() cannot be used with null_buffers()

Reported by: Dmitry Goncharov <dgoncharov@…> Owned by: chris_kohlhoff
Milestone: To Be Determined Component: asio
Version: Boost 1.40.0 Severity: Not Applicable
Keywords: asio async_read null_buffers Cc:


An attempt to use async_read() with null_buffers() causes the handler to be invoked even when the underlying file descriptor is not yet available for reading.

The following test demonstrates the problem

void test_async_read() {

struct local {

static void on_ready(boost::system::error_code const& error, int* invoked) {

BOOST_CHECK(!error); *invoked = 1;



int p[2]; int const s = pipe(p); BOOST_CHECK(0 == s);

boost::asio::io_service ios; boost::asio::posix::stream_descriptor sd(ios, p[0]); ios.reset(); int invoked = 0; boost::asio::async_read(sd, boost::asio::null_buffers(), boost::bind(&local::on_ready, _1, &invoked)); ios.poll_one(); BOOST_CHECK(!invoked); doesn't pass


This test doesn't pass on linux using either epoll or select multiplexing mechanism. This test also doesn't pass on freebsd using either kqueue or select multiplexing mechanism.


Change History

comment:1 Changed 7 years ago by jkp@…

  • Severity changed from Problem to Regression

I can also confirm that this is the case on OS X. The question I have is whether the change is intended? The new documentation seems to imply it is:

If the total size of all buffers in the sequence mb is 0, the asynchronous read operation shall complete immediately and pass 0 as the argument to the handler that specifies the number of bytes read.

Also, the changelist for 1.40.0 says the following:

Changed the buffered*_stream<> templates to treat 0-byte reads and writes as no-ops, to comply with the documented type requirements for SyncReadStream, AsyncReadStream, SyncWriteStream and AsyncWriteStream.

It's unclear what the intendended behaviour is from these two snippets. Certainly pre 1.40.0 you could call async_read with null_buffers and get a callback when some new data had arrived. This is extremely useful functionality, esp for code that has layered other streams on-top of the asio ones. Right now I have no way to check for data (async) without reading it off the socket.

comment:2 Changed 7 years ago by chris_kohlhoff

  • Severity changed from Regression to Problem

Not a regression. The null_buffers() type never worked with async_read().

You may confirm that it doesn't work by making the following changes to the nonblocking example:

@@ -117,7 +117,8 @@

if (session_impl_.want_read() && !read_in_progress_) {

read_in_progress_ = true;

  • socket_.async_read_some(

+ boost::asio::async_read(socket_, + socket_.async_read_some(

boost::asio::null_buffers(), boost::bind(&connection::handle_read,


@@ -138,6 +139,8 @@

void handle_read(boost::system::error_code ec) {

+ printf("handle_read\n"); +

read_in_progress_ = false;

Notify third party library that it can perform a read.

I just checked against 1.39.

comment:3 Changed 7 years ago by chris_kohlhoff

  • Type changed from Bugs to Feature Requests
  • Severity changed from Problem to Not Applicable
  • Milestone changed from Boost 1.41.0 to To Be Determined

The null_buffers type is only intended for use with async_read_some() and async_write_some() on the "lowest layer", i.e. the socket or descriptor. It is not part of any of the stream type requirements, and so not supported by composed operations such as async_read.

If it worked with the buffered*_stream<> templates then that was just a side effect of the 0-byte read/write bug.

It may or may not be useful to support null_buffers as part of the stream type requirements. I'm reclassifying this as a feature request as something to think about in the future.

In any case:

Right now I have no way to check for data (async) without reading it off the socket.

is not correct. It works just fine if you use async_read_some() on the socket.


Add a comment

Modify Ticket

Change Properties
<Author field>
as new

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.