Friday, November 10, 2006

Buffer debugging

Some standard library implementations, such as the one that ships with MSVC 8.0, provide a nifty feature called iterator debugging. What this means is that the validity of your iterators is checked at runtime. If you try to use an iterator that has been invalidated, you'll get an assertion. For example:
std::vector<int> v(1)
std::vector<int>::iterator i = v.begin();
v.clear(); // invalidates iterators
*i = 0; // assertion!
Boost.Asio now takes advantage of this feature to add buffer debugging. Consider the following code:
void dont_do_this()
{
std::string msg = "Hello, world!";
asio::async_write(sock, asio::buffer(msg), my_handler);
}
When you call an asynchronous read or write you need to ensure that the buffers for the operation are valid until the completion handler is called. In the above example, the buffer is the std::string variable msg. This variable is on the stack, and so it goes out of scope before the asynchronous operation completes. If you're lucky, your application will crash. Often you will get random failures.

With the new buffer debug checking, however, Boost.Asio stores an iterator into the string until the asynchronous operation completes, and then dereferences it to check its validity. In the above example you get an assertion failure just before Boost.Asio tries to call the completion handler.

This feature has only been tested with MSVC 8.0 so far, but it should work with any other implementation that supports iterator debugging. Obviously there's a performance cost to this checking, so it's only enabled in debug builds. You can also explicitly disable it by defining BOOST_ASIO_DISABLE_BUFFER_DEBUGGING (or ASIO_DISABLE_BUFFER_DEBUGGING if you're using standalone asio).

4 comments:

andi said...

Hi Chris!

First of all, thanks for the great library!

I just wondered about the behaviour of this buffer debugging thing if the buffer length is zero, e.g.:

[...]
string content = ...
array<asio::const_buffer, 2> buffers = {
asio::buffer(header_ptr, sizeof(header_t)),
asio::buffer(content)
};
asio::async_write(socket_, buffers, boost::bind(...));

This is what I tried to do in my prototype I'm currently building.
Well, the problem I ran into is that the content string would sometimes have length 0, and that triggered an assertion failure because (obviously) the iterator could not be dereferenced then.
So, I wondered whether this is the intended behaviour (in other words: a feature, not a bug)?

chris said...

Hi Andi,

Actually I fixed this bug not so long ago:

http://asio.cvs.sourceforge.net/asio/asio/include/asio/buffer.hpp?r1=1.22&r2=1.23

chris said...

Let's try that link again:

diff for bug fix

andi said...

Oh! Thanks for telling and good luck with your async' arts!