During the second read from the socket I get a read error.
void ClientWindow::on_button_send_clicked()
{
auto message = std::make_shared<std::string>(ui->plainTextEdit->toPlainText().toStdString());
auto message_size = std::make_shared<short>(static_cast<short>(message->size()));
if(*message_size==0)
return;
_socket.async_write_some(boost::asio::buffer(message_size.get(),sizeof(*message_size)),
[this,message](const boost::system::error_code& error, std::size_t)
{
if(!error){
emit clearPlainTextEdit();
qDebug()<<message->size();
qDebug()<<*message;
_socket.async_write_some(boost::asio::buffer(message->data(),message->size()),
[this](const boost::system::error_code& error, std::size_t)
{
if(error)
emit settingStatusBarMessage(error.message() + ": sending size of message errorn");
});
}else
emit settingStatusBarMessage(error.message() + ": sending message errorn");
});
}
At the line _socket.async_write_some(boost::asio::buffer(message->data(),message->size()),
I am transferring to another file xmemory
and I get the error here:
for (auto _Pnext = _STD exchange(_Myproxy->_Myfirstiter, nullptr); _Pnext; _Pnext = _Pnext->_Mynextiter) {
_Pnext->_Myproxy = nullptr;
}
error text:
Exception at 0x7ffbd991efb, code: 0xxc0000005: read access violation at: 0xffffffffffffffff, flagx=0x0 (first chance).
As far as I understand, the error is not on the server side.
I store a smart pointer by value in a lambda function and check its contents and size before doing so, but I still get an error. I also tried using object attributes instead of smart pointers, but the error was the same.
2
Removing all the noise it is easy to see the bug.
auto message = std::make_shared<std::string>(...);
auto message_size = std::make_shared<short>(...);
_socket.async_write_some(boost::asio::buffer(message_size.get(),sizeof(*message_size)),
[this,message](...)
{
...
});
You are writing message_size
asynchronously and capturing only message
, so message_size
is deleted at the end of scope, before the async write even starts. (async writes happen in the future, likely after the function returns)
you need to capture both to extend their lifetime until the async write is done, also the second async write need to capture message
to extend its lifetime until it is done writing it.
Ahmed is right. Much simpler though to combine the writes:
void ClientWindow::on_button_send_clicked()
{
auto message = std::make_shared<std::string>(ui->plainTextEdit->toPlainText().toStdString());
short size = message->length();
message->insert(0, reinterpret_cast<char*>(&size), sizeof(size)); // TODO endianness
async_write(_socket, boost::asio::buffer(*message),
[this, message](boost::system::error_code const& error, size_t /*transferred*/) {
// ...
});
}
NOTE async_write_some
never promises to write the whole buffer anyways. boost::asio::async_write
is a composed operation that ensures the transfer completes.
I’d also suggest making message
a member instead of dynamically allocated+refcounted.
And don’t forget about endianness for the length prefix.