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

使用shared_ptr创建Boost.Mysql连接对象时触发访问违例问题排查

问题分析:使用shared_ptr管理boost::mysql连接触发访问违例

问题描述

我编写了一段用shared_ptr管理boost::mysql::tcp_ssl_connection的代码,希望连接在应用运行全程保持,程序结束时关闭。但调试中触发了访问违例错误,注释创建shared_ptr的代码后错误消失,请问是否是无法在内存中创建连接资源导致的?

代码实现

class DatabaseProcess : public MainframeComponent
{
public:
    // MainframeComponent dispatch module type is set to Main because DatabaseProcess doesn't run on its own thread.
    DatabaseProcess(boost::asio::io_context &io_context) : _io_context(io_context), MainframeComponent(Horizon::System::RUNTIME_DATABASE) { }
    ~DatabaseProcess() 
    { 
        // Close connection object.
        if (_connection != nullptr) {
            _connection->close();
            _connection.reset();
        }

    }
    void initialize(int segment_number = 1) override { HLog(error) << "Database not configured"; }
    void initialize(int segment_number, std::string host, int port, std::string user, std::string pass, std::string database)
    {
        try {
            boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);
            _connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);
            boost::asio::ip::tcp::resolver resolver(_io_context.get_executor());
            auto endpoints = resolver.resolve(host, std::to_string(port));
            boost::mysql::handshake_params params(user, pass, database);
            _connection->connect(*endpoints.begin(), params);
        } catch (boost::mysql::error_with_diagnostics &error) {
            HLog(error) << error.what();
        }

        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, true);
    }

    void finalize(int segment_number = 1) override 
    {
        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, false);
    }

    std::shared_ptr<boost::mysql::tcp_ssl_connection> get_connection() { return _connection; }

    bool is_initialized() { return _is_initialized.load(); }
protected:
    std::shared_ptr<boost::mysql::tcp_ssl_connection> _connection{nullptr};
    boost::asio::io_context &_io_context;
    std::atomic<bool> _is_initialized;
};

调试输出

Exception thrown at 0x00007FFA63663FAA (ntdll.dll) in ZoneSystemTest.exe: 0xC0000005: Access violation writing location 0x0000000000000024.
The program '[27192] ZoneSystemTest.exe' has exited with code 0 (0x0).

触发错误的关键代码行:
_connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);


问题根源

并非无法创建连接资源导致的错误,核心问题在于ssl_ctx的生命周期不匹配:

  • 在initialize函数中,ssl_ctx是局部变量,函数执行完毕后会被销毁。
  • boost::mysql::tcp_ssl_connection的构造函数接受的是boost::asio::ssl::context的引用,意味着_connection会持有对这个已销毁局部变量的引用。后续任何对_connection的操作(比如析构时调用close())都会访问已释放的内存,直接触发访问违例。

此外还有两个潜在问题:

  1. 成员变量_is_initialized未在构造函数中初始化,属于未定义行为,可能导致逻辑错误。
  2. _connection->close()如果是异步操作,未等待完成就销毁连接,可能引发资源访问问题。

修复方案

1. 调整ssl_ctx的生命周期

将ssl_ctx提升为类的成员变量,确保其生命周期与_connection一致:

class DatabaseProcess : public MainframeComponent
{
public:
    DatabaseProcess(boost::asio::io_context &io_context) 
        : _io_context(io_context), 
          _ssl_ctx(boost::asio::ssl::context::tls_client),  // 初始化SSL上下文
          MainframeComponent(Horizon::System::RUNTIME_DATABASE),
          _is_initialized(false)  // 初始化原子变量
    { }

    // ... 其他成员函数 ...

protected:
    std::shared_ptr<boost::mysql::tcp_ssl_connection> _connection{nullptr};
    boost::asio::io_context &_io_context;
    std::atomic<bool> _is_initialized;
    boost::asio::ssl::context _ssl_ctx;  // 新增成员变量
};

修改initialize函数,使用类成员的_ssl_ctx:

void initialize(int segment_number, std::string host, int port, std::string user, std::string pass, std::string database)
{
    try {
        // 移除局部的ssl_ctx,使用类成员变量
        _connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), _ssl_ctx);
        boost::asio::ip::tcp::resolver resolver(_io_context.get_executor());
        auto endpoints = resolver.resolve(host, std::to_string(port));
        boost::mysql::handshake_params params(user, pass, database);
        _connection->connect(*endpoints.begin(), params);
    } catch (boost::mysql::error_with_diagnostics &error) {
        HLog(error) << error.what();
        _is_initialized.store(false);  // 初始化失败时重置状态
        return;
    }

    _is_initialized.store(true);  // 直接赋值,无需compare_exchange_strong(单线程初始化场景)
}

2. 优化析构逻辑

如果close()是异步操作,需确保操作完成后再销毁连接:

~DatabaseProcess() 
{ 
    if (_connection != nullptr) {
        // 若close为异步操作,需同步等待完成(示例,具体需参考boost::mysql文档)
        boost::asio::post(_io_context.get_executor(), [this]() {
            _connection->close();
            _connection.reset();
        });
        _io_context.run_one();  // 等待close操作完成
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 08:08:11