我正在为 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()
malloc
或 free
中的任何崩溃几乎都是堆损坏的标志(例如释放非堆内存、释放两次内存或在内存被释放后写入内存)被释放或超出分配 block 的末尾)。
在 Valgrind 下运行您的程序,它会直接指出您的错误。
或者您可以设置 MALLOC_CHECK_
环境变量,并让 glibc 在检测到损坏时中止 (documentation)。这通常不如 Valgrind 有用,但可以快速确认您确实确实存在堆损坏,并且可以为您提供足够的线索来查找和修复错误。
关于c++ - mysql_stmt_store_result() 上的 MySQL C API 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20828372/