I have the following code which encompasses a boost::mysql connection using a shared_ptr. I want to keep the connection object for the duration of the application’s runtime. I want the application to then close the connection on the end of the runtime. However, I get an access violation when debugging the process.
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;
};
Debug output:
Running 1 test case...
*** No errors detected
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).
The lines responsible significantly are –
_connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);
When commented, the error goes away. Is it because we can’t create a resource in memory of the connection object?
2
Answers
The io_context belonged to a class which was the child of the class that holds the DatabaseProcess. So the answer was to change the io_context to be a member of that class and making sure that the destruction of DatabaseProcess occurs before the destruction of that class.
The lifetimes of objects are not guarded well.
the
_io_context
member is initialized AFTER the base class, you want to fix the order of the initializers to reflect thisthe
ssl_ctx
is destructed before the end ofinitialize
. It probably needs to be a member objectyou probably want to use all the resolver endpoints in the connection attempt:
most importantly, the lifetime of the
io_context
object is not shown, but needs to be guarded.Everything could be greatly simplified by avoiding references, two-step initialization and dynamic allocation.
Some Fixes
Some of the above fixed:
Live On Coliru