user869210
user869210

Reputation: 231

Bug of compiler or boost library?

This program (it has been narrowed down from a larger program) always crashes after compiled in vs2008 Release(Win32) mode under windows 7. I am not familiar with assembly code and don't know it's a bug of compiler or boost::ends_with or boost::asio::buffers_iterator. It can be compiled and executed with g++ in Ubuntu without any problem.

People said it's very unlikely to be compiler's bug, but when compiled in debug moded(or disable optimization), the problem does disappear.

I have been stuck with this problem for quite a few hours. Any help is appreciated. Thanks in advance.

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/algorithm/string.hpp>

typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator_t;
typedef boost::iterator_range<iterator_t> range_t;
static const std::string LINE_END_MARK = "\r\n";

int main(int argc, char* argv[])
{
    boost::asio::streambuf _buf;
    std::ostream os(&_buf);
    os<<"END\r\n";

    iterator_t cursor = boost::asio::buffers_begin(_buf.data());
    iterator_t end = boost::asio::buffers_end(_buf.data());

    std::ostream_iterator<char> it(std::cout," ");
    std::copy(LINE_END_MARK.begin(), LINE_END_MARK.end(), it);

    range_t r(cursor, end);
    if(!boost::ends_with(r, LINE_END_MARK))
        return 0;
    return 1;
}

Upvotes: 9

Views: 669

Answers (2)

Shane Powell
Shane Powell

Reputation: 14158

It doesn't work because 'range_t r(cursor, end)' is a range of "buffers" not a range of characters. So you are comparing a list of buffer pointers with each character in LINE_END_MARK.

If crashes in release mode under win32 because in windows you end up de-referencing a null pointer causing the crash.

boost asio has this concept of multiple buffers, but currently it's not really used. If you look at the implementation if only really uses 'const_buffers_1' or 'mutable_buffers_1' which is basically a list of 1 buffer.

I assume you want to compare the contents of the buffer, not a list of buffers range.

So you want to do something like:

typedef boost::iterator_range<const char*> range_t;
range_t r(boost::asio::buffer_cast<const char*>(_buf.data()), boost::asio::buffer_cast<const char*>(_buf.data()) + boost::asio::buffer_size(_buf.data()));
if(!boost::ends_with(r, LINE_END_MARK))
    return 0;
return 1;

Upvotes: 1

adzm
adzm

Reputation: 4136

Edit: I misread the code, sorry.

Your cursor and end iterators are pointing to invalid memory. You modified the underlying streambuf which reallocated during the copy to the output iterator. asio streambuf lets you access the raw memory for performance reasons, but the caveat is you have to worry about things like this.

Debug and release will change the way allocation and deallocation behave with regards to the underlying size of the allocated block and how memory may be fenced, guarded, initialized, aligned, etc.

Construct your iterators after the copy operation to fix your problem.

Upvotes: 1

Related Questions