You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket读取访问违例:异步写入触发0xc0000005错误求助

Socket异步写入触发内存访问错误的排查与解决

问题场景

使用Boost.Asio进行Socket第二次异步写入时,触发读取访问违例错误(错误代码0xc0000005,错误地址0xffffffffffffffff),程序跳转至xmemory文件的迭代器处理代码段。

相关发送代码

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 error");
                            });
                 }else
                      emit settingStatusBarMessage(error.message() + ": sending message error");
            });
}

触发错误的xmemory代码片段

for (auto _Pnext = _STD exchange(_Myproxy->_Myfirstiter, nullptr); _Pnext; _Pnext = _Pnext->_Mynextiter) {
    _Pnext->_Myproxy = nullptr;
}

已尝试的操作

  • 在lambda中按值捕获std::shared_ptr确保对象生命周期
  • 提前检查消息内容和大小
  • 改用对象属性替代智能指针,问题依旧

问题根源分析

  1. 内层lambda未捕获message导致内存提前释放:
    外层lambda捕获了message,但内层lambda仅捕获this。当外层lambda发起第二个异步写入后立即执行完毕,message的引用计数减1,若没有其他持有者,std::string对象会被销毁,而后台异步写入操作仍在访问已释放的内存,触发访问违例。

  2. async_write_some的使用误区:
    该函数仅保证写入部分数据就触发handler,无法确保完整发送消息,可能导致后续逻辑混乱,不适合需要完整传输数据的场景。

  3. 潜在的对象生命周期风险:
    若ClientWindow或_socket在异步操作执行期间被销毁,也会导致野指针访问错误。


解决方案

1. 内层lambda捕获message

确保第二个异步写入操作期间,message的生命周期被延长,避免内存提前释放:

_socket.async_write_some(boost::asio::buffer(message->data(), message->size()),
    [this, message](const boost::system::error_code& error, std::size_t)
    {
        if(error)
            emit settingStatusBarMessage(error.message() + ": sending message content error");
    });

2. 改用async_write替代async_write_some

async_write会保证将整个buffer的数据发送完成才触发handler,更适合完整传输数据的场景:

// 发送消息长度
boost::asio::async_write(_socket, 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;
            // 发送消息内容
            boost::asio::async_write(_socket, boost::asio::buffer(message->data(), message->size()),
                [this, message](const boost::system::error_code& error, std::size_t)
                {
                    if(error)
                        emit settingStatusBarMessage(error.message() + ": sending message content error");
                });
        }else
            emit settingStatusBarMessage(error.message() + ": sending message size error");
    });

3. 确保ClientWindow生命周期覆盖异步操作

让ClientWindow继承std::enable_shared_from_this,通过捕获shared_ptr避免对象被提前销毁:

// 类定义修改
class ClientWindow : public QMainWindow, public std::enable_shared_from_this<ClientWindow>
{
    // ... 原有成员
};

// 修改lambda捕获逻辑
_socket.async_write_some(boost::asio::buffer(message_size.get(), sizeof(*message_size)),
    [self = shared_from_this(), message](const boost::system::error_code& error, std::size_t)
    {
        if(!error){
            emit self->clearPlainTextEdit();
            qDebug()<<message->size();
            qDebug()<<*message;
            self->_socket.async_write_some(boost::asio::buffer(message->data(), message->size()),
                [self, message](const boost::system::error_code& error, std::size_t)
                {
                    if(error)
                        emit self->settingStatusBarMessage(error.message() + ": sending message content error");
                });
        }else
            emit self->settingStatusBarMessage(error.message() + ": sending message size error");
    });

验证步骤

  1. 先修改内层lambda捕获message,测试是否消除内存错误
  2. 若问题解决,替换为async_write优化发送逻辑
  3. 最后检查对象生命周期,确保异步操作期间相关对象未被销毁

内容的提问来源于stack exchange,提问作者Danek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:22:17