c++ - mysql_stmt_store_result() 上的 MySQL C API 崩溃

标签 c++ mysql c crash gdb

我正在为 MySQL C API 制作一个 C++ 包装器,并在使用准备好的语句查询时随机崩溃。

一切正常,但有大约 10% 的几率在 mysql_stmt_store_result() 上崩溃。似乎只有在重复使用相同的准备好的语句时它才会崩溃,但我不确定。相同的代码有时可以在同一个 stmt 上一次执行 50 个查询,而另一个执行 5 个查询。但我从来没有让它在第一次查询时崩溃。

崩溃日志:

#0  malloc_consolidate (av=0x7ffff0000020) at malloc.c:5137
        fb = 0x7ffff0000030
        maxfb = 0x7ffff0000070
        p = 0x8
        nextp = 0x8
        unsorted_bin = 0x7ffff0000078
        first_unsorted = 0x7ffff0000078
        nextchunk = 0x7ffff0011280
        size = 12672
        nextsize = 8176
        prevsize = <value optimized out>
        bck = 0x7ffff0000078
        fwd = 0x7ffff0000078
        __func__ = "malloc_consolidate"
#1  0x00007ffff5b06594 in _int_malloc (av=0x7ffff0000020, bytes=4064)
    at malloc.c:4373
        nb = 4080
        idx = 4026531960
        bin = 0x8
        victim = 0x7ffff0000020
        size = <value optimized out>
        victim_index = <value optimized out>
        remainder = <value optimized out>
---Type <return> to continue, or q <return> to quit---
        remainder_size = <value optimized out>
        block = <value optimized out>
        bit = <value optimized out>
        map = <value optimized out>
        fwd = <value optimized out>
        bck = <value optimized out>
        errstr = <value optimized out>
        __func__ = "_int_malloc"
#2  0x00007ffff5b08c70 in *__GI___libc_malloc (bytes=4064) at malloc.c:3661
        ar_ptr = 0x7ffff0000020
        victim = 0x30
        __func__ = "__libc_malloc"
#3  0x00007ffff7051ca2 in my_malloc () from /usr/lib/libmysqlclient.so.18
No symbol table info available.
#4  0x00007ffff704d5c5 in alloc_root () from /usr/lib/libmysqlclient.so.18
No symbol table info available.
#5  0x00007ffff702ca96 in cli_read_binary_rows ()
   from /usr/lib/libmysqlclient.so.18
No symbol table info available.
#6  0x00007ffff702e5b7 in mysql_stmt_store_result ()
   from /usr/lib/libmysqlclient.so.18
No symbol table info available.
#7  0x00000000005c3a79 in ResultSet (this=0x7ffff000e0d0,
---Type <return> to continue, or q <return> to quit---
    result=0x7ffff000e030, stmt=0x7ffff0008a10, fieldCount=3)
    at /var/coins/poolserver/cmake/src/server/shared/MySQL/QueryResult.cpp:34
        bind = 0x52bfc4c1
#8  0x00000000005c1b22 in MySQL::DatabaseConnection::Query (this=0x8e8b00,
    stmt=0x7ffff000de50)
    at /var/coins/poolserver/cmake/src/server/shared/MySQL/DatabaseConnection.cpp:247
        result = 0x7ffff000e030
        resultSTMT = 0x7ffff0008a10
        fieldCount = 3

如您所见,stmt 指针不为空。

部分代码:

查询:

ResultSet* DatabaseConnection::Query(PreparedStatement* stmt)
{
    MYSQL_RES* result = NULL;
    MYSQL_STMT* resultSTMT = NULL;
    uint32 fieldCount = 0;

    if (!_Query(stmt, &result, &resultSTMT, fieldCount))
        return NULL;

    if (mysql_more_results(_mysql))
        mysql_next_result(_mysql);

    return new ResultSet(result, resultSTMT, fieldCount);
}

bool DatabaseConnection::_Query(PreparedStatement* stmt, MYSQL_RES** result, MYSQL_STMT** resultSTMT, uint32& fieldCount)
{
    if (!_mysql)
        return false;

    ConnectionPreparedStatement* cstmt = GetPreparedStatement(stmt->_index);

    if (!cstmt) {
        sLog.Error(LOG_DATABASE, "STMT id: %u not found!", stmt->_index);
        return false;
    }

    cstmt->BindParameters(stmt);

    MYSQL_STMT* mSTMT = cstmt->GetSTMT();
    MYSQL_BIND* mBIND = cstmt->GetBind();

    if (mysql_stmt_bind_param(mSTMT, mBIND))
    {
        uint32 lErrno = mysql_errno(_mysql);
        sLog.Error(LOG_DATABASE, "STMT Execute Error[%u]: %s", lErrno, mysql_stmt_error(mSTMT));

        if (_HandleMySQLErrno(lErrno))  // If it returns true, an error was handled successfully (i.e. reconnection)
            return Execute(stmt);       // Try again

        cstmt->ClearParameters();
        return false;
    }

    if (mysql_stmt_execute(mSTMT))
    {
        uint32 lErrno = mysql_errno(_mysql);
        sLog.Error(LOG_DATABASE, "STMT Execute Error[%u]: %s", lErrno, mysql_stmt_error(mSTMT));

        if (_HandleMySQLErrno(lErrno))  // If it returns true, an error was handled successfully (i.e. reconnection)
            return _Query(stmt, result, resultSTMT, fieldCount);       // Try again

        cstmt->ClearParameters();
        return false;
    }

    cstmt->ClearParameters();

    *result = mysql_stmt_result_metadata(mSTMT);
    fieldCount = mysql_stmt_field_count(mSTMT);
    *resultSTMT = mSTMT;

    return true;
}

结果集:

ResultSet::ResultSet(MYSQL_RES* result, MYSQL_STMT* stmt, uint32 fieldCount) :
_fieldCount(fieldCount), _currentRow(0)
{
    if (!result)
        return;

    if (mysql_stmt_store_result(stmt)) { // Crash here
        sLog.Error(LOG_DATABASE, "mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", mysql_stmt_error(stmt));
        return;
    }

    /* further code */
}

这些只是涉及崩溃的部分代码。完整代码可在此处找到:https://github.com/Intel/poolserver/tree/master/src/server/shared/MySQL

我已经尝试解决这个问题 3 天了,但没有成功。有谁知道发生了什么事吗?

最佳答案

Everything works fine but with ~10% chance it crashes on mysql_stmt_store_result()

mallocfree 中的任何崩溃几乎都是堆损坏的标志(例如释放非堆内存、释放两次内存或在内存被释放后写入内存)被释放或超出分配 block 的末尾)。

Valgrind 下运行您的程序,它会直接指出您的错误。

或者您可以设置 MALLOC_CHECK_ 环境变量,并让 glibc 在检测到损坏时中止 (documentation)。这通常不如 Valgrind 有用,但可以快速确认您确实确实存在堆损坏,并且可以为您提供足够的线索来查找和修复错误。

关于c++ - mysql_stmt_store_result() 上的 MySQL C API 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20828372/

相关文章:

php - 将查询结果存储为 php 变量

mysql - 范围外的子查询值

c++ - 在线程之间重定向标准输入/输出

iPhone 设备上的 C 套接字崩溃。 EXC_BAD_ACCESS

c++ - 为什么当我删除其他字符时最后一个字符会加倍,如何防止这种情况发生?

c++ - 生成 0 到 10 之间的随机数

c++ - 在 Geany 中使用 OpenGL 时获取 undefined reference

c++ - 渲染到小 map 的纹理,directX

mysql - 条目中以逗号分隔的循环子字符串

c - 在 if block 中声明变量的确切效果