mysql connector/c++:get\u driver\u instance()在从全局构造调用时崩溃

b1zrtrql  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(365)

我在windows10上使用mysql连接器/c++。我发现当我打电话的时候 get_driver_instance 从全局对象的c'tor开始,它只是抛出异常:访问冲突读取位置。
示例代码:


# 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;
}

引发的异常类似于:
sample.exe中0x000007f6be17485d处出现未处理的异常:0xc000005:访问冲突读取位置0x00000000008。
崩溃时的堆栈跟踪:

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

令人惊讶的是,这只发生在调试构建中。然而,这与本问题中提出的情况不同。我已经确定我正在链接调试生成的连接器库。如果我示例化同一个对象 someclass_instance 但在main函数中,它并没有崩溃。这真的很奇怪。我怀疑与crt初始化有关,但不确定是否通过。
注意:我花了好几个小时才弄明白。这是真正的问题。在投票之前,请至少尝试一次代码。
如果有人能发光就好了。

zbq4xfa0

zbq4xfa01#

不能依赖于静态初始化不同类的顺序(例如,在您的情况下,调试版本和发布版本之间的顺序是不同的)。
这就是所谓的静态初始化顺序“惨败”。
必须避免在静态初始化器中调用任何依赖于静态初始化的代码。
mysql驱动程序有各种静态初始化器,可能是名称到驱动程序的Map引起了问题。
避免这种情况的一种方法是使用延迟构造的单例,该单例使用的是函数级静态,该静态在第一次调用函数时初始化:

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;
}

请注意 someclass_instance() 如果您不使用最新的编译器(例如visual studio 2013或更早版本),则可能不是线程安全的,如果是这种情况,您需要确保在启动使用该函数的其他线程之前从单个线程调用函数一次。
您还可以通过在内部移动驱动程序Map来修复mysql代码 get_driver_instance_by_name (或者提交一份bug报告,让他们帮你做)。

相关问题