Boost logo

Boost :

Subject: [boost] [asio] [function] Strange corruption error with boost::function and asio
From: Zachary Turner (divisortheory_at_[hidden])
Date: 2010-01-29 17:18:57


I'm not sure if I'm experiencing a bug in boost, bug in compiler (VS 9.0
service pack 1), or bug somewhere else, but I'm having trouble reading
boost::function code enough to be able to figure out.

A little background:

I'm using boost::asio to read from a disk, and then boost::asio to write
results to a socket. Everything works completely fine most of the time, but
in some cases there's an error on my server (which is largely irrelevant
here as it's not even written in C++) and the server crashes unexpectedly.
I suspect the error is occuring while I'm in the middle of an asynchronous
network write, because the very first odd behavior surfaces in my network
write completion routine. I can go into more detail about how I'm using
boost::function and boost::asio in conjunction if necessary, but for now
I'll just post the bare minimum needed to be able to make any sense at all
of what I'm doing (which is still alot, my apologies for the length).
Anyway:

- my completion routine has the following signature:

void async_service_write_network::write_data_handler(asio_handler
wrapped_handler, boost::system::error_code error, size_t bytes_transferred)

- asio_handler (referenced in the previous signature) is defined as follows:

typedef boost::function<void (boost::system::error_code, size_t)>
asio_handler;

Which is exactly the same but contains a wrapped handler at the front so I
can privately intercept the handler at various points along the chain, and
then have the private handler do arbitrary work then invoke the wrapped
handler. I do this with boost::bind as follows

    asio_handler wrapped_handler = boost::bind(
        &async_service_write_network::write_data_handler,
        this,
        handler,
        _1, _2);

    socket_.async_send(
        buffer,
        boost::bind(
            wrapped_handler,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));

To explain the odd behavior, I've put a breakpoint in write_data_handler.
Quick version if you don't feel like reading, the function arguments seem to
be being corrupted either by boost::bind or boost::function.

Long version, looking at the values of the arguments shows the following:

   error {m_val=23843184 m_cat=0x000000000000305d }
boost::system::error_code
        m_val 23843184 int
        m_cat 0x000000000000305d const boost::system::error_category *
        boost::noncopyable_::noncopyable {...}
boost::noncopyable_::noncopyable
        __vfptr CXX0030: Error: expression cannot be evaluated

So I move one level up the callstack. This puts me in:

template<class R, class T, class A1, class A2, class A3
BOOST_MEM_FN_CLASS_F> class BOOST_MEM_FN_NAME(mf3)
{
    //Boost 1.39 mem_fn_template.hpp line 384
    R operator()(T * p, A1 a1, A2 a2, A3 a3) const
    {
        BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3);
    }
}

Examining a1, a2, and a3 shows that they are what they appear to be.
Walking one more level up the callstack and this is no longer the case:

template< class A1, class A2, class A3, class A4 > class list4: private
storage4< A1, A2, A3, A4 >
{
    //Bind.hpp line 450
    template<class F, class A> void operator()(type<void>, F & f, A & a,
int)
    {
        unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_],
a[base_type::a3_], a[base_type::a4_]);
    }
}

Examining the contents of 'a', I see this:

- a {...} boost::_bi::list2<boost::system::error_code
&,unsigned __int64 &> &
     - boost::_bi::storage2<boost::system::error_code &,unsigned
__int64 &> {a2_=12381 } boost::_bi::storage2<boost::system::error_code
&,unsigned __int64 &>
          - boost::_bi::storage1<boost::system::error_code &>
{a1_={...} } boost::_bi::storage1<boost::system::error_code &>
               - a1_ {m_val=0 m_cat=0x000000014000ac48 }
boost::system::error_code &
                               m_val 0 int
                     + m_cat 0x000000014000ac48
system_category_const const boost::system::error_category *
                        a2_ 12381 unsigned __int64 &

Somehow this error code is becoming corrupted. It is clearly has an m_val
of 0 here, and an m_cat of 0x14000ac48 here, and in the very next function
on the call stack, it has an m_val of 23843184, and an m_cat of 0x305d.

Am I missing something obvious or is there an actual boost/compiler bug
going on here?


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk