Mar 27, 2009

boost asio for windows pipe bug -- ERROR_MORE_DATA

I encountered another asio bug today.
I created a pipe server and used a pipe client to send data to the server.
The server read 128 bytes for each read, but the client sends 65536 bytes for each write. When the server read the data, ::ReadFile returns ERROR_MORE_DATA.
Then it just crashed.

The root cause is at function "async_read_some_at" in the file "win_iocp_handle_service.hpp".


DWORD bytes_transferred = 0;
ptr.get()->Offset = offset & 0xFFFFFFFF;
ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_,
boost::asio::buffer_cast(buffer),
static_cast(boost::asio::buffer_size(buffer)),
&bytes_transferred, ptr.get());
DWORD last_error = ::GetLastError();
if (!ok && last_error != ERROR_IO_PENDING)
{
boost::asio::io_service::work work(this->get_io_service());
ptr.reset();
boost::system::error_code ec(last_error,
boost::asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
{
ptr.release();
}
}


In the above code,

if (!ok && last_error != ERROR_IO_PENDING)
{
boost::asio::io_service::work work(this->get_io_service());
ptr.reset();
boost::system::error_code ec(last_error,
boost::asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}


Checks for any error. When last_error != ERROR_IO_PENDING, the function assumes that the call to ::ReadFile is failed, so it release ptr immediately. But when last_error is ERROR_MORE_DATA, the call is successful and the ReadComplete event will still be put in the complete queue. Since the ptr has been released, the LPOVERLAPPED returned by ::GetQueuedCompletionStatus points to invalid location and is causes crash.

The fix is simple, just change the code to

if (!ok && (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) )
{
boost::asio::io_service::work work(this->get_io_service());
ptr.reset();
boost::system::error_code ec(last_error,
boost::asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}

1 comments:

Layman said...

I'm struggling with using boost::asio with windows pipes. Can you point me to some good documentation?

Thanks

 
TEMPLATE HACKS AND TWEAKS BY [ METAMUSE ] BLACKCAT 1.1
/scripts/shBrushJScript.js'/>