Boost logo

Boost Users :

Subject: Re: [Boost-users] echo server modification causes undefined behaviour
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2017-09-07 22:33:47


On 7/09/2017 22:21, Peter Koukoulis via Boost-users wrote:
> thanks for the info, I've modified the do_read function as follows:
>
>   void do_read() {
>     excep_log( "Start reading");
>     boost::asio::async_read_until(sk, receive_data, '\n',
>         [this](const boost::system::error_code& ec, std::size_t
> bytes_transferred) {
>               if (!ec) {
>                 boost::asio::streambuf::const_buffers_type bufs =
> receive_data.data();
>                 std::string str(boost::asio::buffers_begin(bufs),
> boost::asio::buffers_begin(bufs) + bytes_transferred);
>                 receive_data.consume(bytes_transferred);
>                 excep_log( "SQL Statement: " + str);
>                 do_write(bytes_transferred, rows_affected(str) );
>               }
>             });
>   }
>
> The server still crashes, though the error is no longer a "core dump",
> but a "Segmentation fault".
> The log file generated shows output as follows:
> Start: 0
> 0: Start reading
> 0: SQL �\�
> 7: 22021 ERROR:  invalid byte sequence for encoding "UTF8": 0xba
>
> 7: Before write
>
> As you can see, when a session is started (start function), the
> read_until starts immediately,   but at that point the client has only
> connected and not yet sent a SQL statement (22021 ERROR is a database
> error).
> So how can I start a session, but defer the reading until the client has
> sent an SQL statement ?

Another problem with your original code is that the session is not being
kept alive.

> std::make_shared<session>(std::move(sk))->start();

This creates a shared instance of session and calls start() on it, but
as soon as start() returns it will discard the local reference to the
session -- unless something inside of the start() call keeps a reference
alive, that means the session will probably be deleted before the read
operation completes. (This is why you're getting garbage when the
callback does eventually get called -- it's reading deleted memory.)

The usual technique for keeping a shared_ptr alive is to ensure that you
pass it into the async callback. Call shared_from_this() outside of
your lambda and capture *that* variable instead of capturing 'this'.
You'll need to do the same thing in the write operation as well.

(Capturing 'this' is not sufficient to keep the object alive, as it's
just a raw pointer.)

See the example in
http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net