简体   繁体   中英

MySQL Connector/C++: get_driver_instance() crashes when called from global construct

I'm using MySQL Connector/C++ on Windows 10. I observed that when I call get_driver_instance from c'tor of global object, it simply crashes throwing exception: Access violation reading location.

Sample code:

#define CPPCONN_LIB_BUILD // Need to include this as we are linking mysql connector in static library
#include "MySQL\Src\mysql-connector-c++-1.1.5\cppconn\driver.h"

#pragma comment(lib,"MySQL\\Src\\mysql-connector-c++-1.1.5\\BLD\\driver\\Debug\\mysqlcppconn-static.lib")
#pragma comment(lib,"MySQL\\Src\\mysql-5.6.24\\BLD\\libmysql\\Debug\\mysqlclient.lib")

struct someclass
{
    sql::Driver *m_pDriver;

    someclass()
    {
        /* Create a connection */
        m_pDriver= get_driver_instance(); // It crashes here
        cout << "print something";
    }
} someclass_instance;

int main(int argc, char** argv) 
{
    // We don't need to do anything here. The problem occurs in the global class constructor which executes before main as we've defined its global instance.

    return 0;
}

Exception thrown is something similar to this:

Unhandled exception at 0x000007F6BE17485D in Sample.exe: 0xC0000005: Access violation reading location 0x0000000000000008.

Stacktrace at the time of crash:

Sample.exe!std::_Tree<class std::_Tmap_traits<class sql::SQLString,class boost::shared_ptr<class sql::mysql::MySQL_Driver>,struct std::less<class sql::SQLString>,class std::allocator<struct std::pair<class sql::SQLString const ,class boost::shared_ptr<class sql::mysql::MySQL_Driver> > >,0> >::_Lbound(class sql::SQLString const &) Unknown
Sample.exe!std::_Tree<class std::_Tmap_traits<class sql::SQLString,class boost::shared_ptr<class sql::mysql::MySQL_Driver>,struct std::less<class sql::SQLString>,class std::allocator<struct std::pair<class sql::SQLString const ,class boost::shared_ptr<class sql::mysql::MySQL_Driver> > >,0> >::lower_bound(class sql::SQLString const &) Unknown
Sample.exe!std::_Tree<class std::_Tmap_traits<class sql::SQLString,class boost::shared_ptr<class sql::mysql::MySQL_Driver>,struct std::less<class sql::SQLString>,class std::allocator<struct std::pair<class sql::SQLString const ,class boost::shared_ptr<class sql::mysql::MySQL_Driver> > >,0> >::find(class sql::SQLString const &)    Unknown
Sample.exe!sql::mysql::get_driver_instance_by_name(char const * const)  Unknown
Sample.exe!sql::mysql::get_driver_instance(void)    Unknown
Sample.exe!get_driver_instance()    Unknown
Sample.exe!someclass::someclass() Line 72   C++
Sample.exe!`dynamic initializer for 'obj''() Line 76    C++
Sample.exe!_initterm(void (void) * * pfbegin, void (void) * * pfend) Line 894   C
Sample.exe!_cinit(int initFloatingPrecision) Line 303   C
Sample.exe!__tmainCRTStartup() Line 227 C
Sample.exe!mainCRTStartup() Line 164    C

Surprisingly this happens only in Debug build. However it is not same case as asked in this question. I've made sure I am linking Debug built connector library. Also if I instantiate same object someclass_instance but inside main function it doesn't crash there. This is really weird. I suspect something related with CRT initialisation but not sure through.

Note: I've spend hours figuring this out. This is genuine issue. Before down-voting appreciate to try the code at least once.

Would be great if anyone can throw light.

You can't rely on the order that different classes are statically initialised (for example in your situation the order is different between debug and release builds).

This is known as the static initialization order 'fiasco' .

You must avoid calling any code in a static initialiser which itself relies on static initialisation.

The MySQL driver has various static initialisers, presumably the one causing you a problem is the map of names to drivers .

One way to avoid this is to use a lazily constructed singleton using a function level static which is initialised the first time the function is called:

struct someclass
{
    sql::Driver *m_pDriver;

    someclass()
    {
        /* Create a connection */
        m_pDriver= get_driver_instance(); // It crashes here
        cout << "print something";
    }

    void foo() {}
};

someclass& someclass_instance()
{
    static someclass instance;
    return instance;
}

int main(int argc, char** argv) 
{
    someclass_instance().foo();
    return 0;
}

Note that someclass_instance() might not be thread safe if you aren't using a recent compiler (eg visual studio 2013 or earlier), if that is the case you need to make sure to call your function once from a single thread before starting other threads that use the function.

You could also fix the MySQL code by moving the driver map inside get_driver_instance_by_name (or submit a bug report asking them to do it for you).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM