zry@huawei:~/src/modules/Connect$ ./newbuild/OpConnectAidTool
\WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.
replace into `process_tracking` (`step_id`,`date`,`status`,`context_data`,`start_time`,`end_time`,`error_log`) values(?,?,?,?,?,?,?)
Incorrect datetime value: '' for column 'end_time' at row 1
WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.
replace into `process_tracking` (`step_id`,`date`,`status`,`context_data`,`start_time`,`end_time`,`error_log`) values(?,?,?,?,?,?,?)
=================================================================
==212612==ERROR: AddressSanitizer: stack-use-after-scope on address 0xffffc8f31e50 at pc 0xffff978997b0 bp 0xffffc8f312d0 sp 0xffffc8f31348
READ of size 11 at 0xffffc8f31e50 thread T0
#0 0xffff978997ac in __interceptor_strlen ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:354
#1 0xffff977bb6c4 in redisFormatSdsCommandArgv /root/temp-z/hiredis-master/hiredis.c:600
#2 0xffff977bcce0 in redisAppendCommandArgv /root/temp-z/hiredis-master/hiredis.c:1164
#3 0xffff977bcec4 in redisCommandArgv /root/temp-z/hiredis-master/hiredis.c:1216
#4 0xaaaaad90210c in zryMyRedisTool::cleanExpiredFields(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (/home/zry/src/modules/Connect/newbuild/OpConnectAidTool+0x10310c)
#5 0xaaaaad8dc744 in CConnectModuleAidTool::SaveProcessTrackingInfo(bool) /home/zry/src/modules/Connect/OpConnectAidTool.cpp:485
#6 0xaaaaad8de9d0 in test_SaveProcessTrackingInfo() /home/zry/src/modules/Connect/OpConnectAidTool.cpp:521
#7 0xaaaaad8dea0c in main /home/zry/src/modules/Connect/OpConnectAidTool.cpp:535
#8 0xffff96c9ae0c in __libc_start_main ../csu/libc-start.c:308
#9 0xaaaaad8d02bc (/home/zry/src/modules/Connect/newbuild/OpConnectAidTool+0xd12bc)
Address 0xffffc8f31e50 is located in stack of thread T0 at offset 384 in frame
#0 0xaaaaad901bf8 in zryMyRedisTool::cleanExpiredFields(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (/home/zry/src/modules/Connect/newbuild/OpConnectAidTool+0x102bf8)
This frame has 10 object(s):
[32, 36) 'cleaned' (line 296)
[48, 64) '<unknown>'
[80, 96) '<unknown>'
[112, 136) '<unknown>'
[176, 200) '<unknown>'
[240, 264) '<unknown>'
[304, 336) 'zsetKey' (line 268)
[368, 400) '<unknown>' <== Memory access at offset 384 is inside this variable
[432, 464) '<unknown>'
[496, 544) 'argv' (line 271)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:354 in __interceptor_strlen
Shadow bytes around the buggy address:
0x200ff91e6370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200ff91e6380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200ff91e6390: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 04 f2
0x200ff91e63a0: 00 00 f2 f2 00 00 f2 f2 00 00 00 f2 f2 f2 f2 f2
0x200ff91e63b0: 00 00 00 f2 f2 f2 f2 f2 00 00 00 f2 f2 f2 f2 f2
=>0x200ff91e63c0: 00 00 00 00 f2 f2 f2 f2 f8 f8[f8]f8 f2 f2 f2 f2
0x200ff91e63d0: 00 00 00 00 f2 f2 f2 f2 00 00 00 00 00 00 f3 f3
0x200ff91e63e0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200ff91e63f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200ff91e6400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x200ff91e6410: f1 f1 f8 f2 f8 f2 f8 f2 01 f2 01 f2 04 f2 04 f2
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==212612==ABORTING
2.1 报错描述
在运行程序时,AddressSanitizer 报告了stack-use-after-scope
错误,具体表现为程序试图访问已经超出作用域的栈内存。这通常是因为某些变量的作用域问题导致的。
2.2 报错现象
运行程序时,AddressSanitizer 报告以下错误:
==212612==ERROR: AddressSanitizer: stack-use-after-scope on address 0xffffc8f31e50 at pc 0xffff978997b0 bp 0xffffc8f312d0 sp 0xffffc8f31348
READ of size 11 at 0xffffc8f31e50 thread T0
调用栈显示错误发生在zryMyRedisTool::cleanExpiredFields
函数中,具体是在调用redisCommandArgv
时。
2.3 报错原因
• 变量作用域问题:
• argv
和zsetKey
的作用域可能在调用redisCommandArgv
时已经结束。
• std::vector
的生命周期问题,导致argv.data()
指向的内存无效。
• std::vector
的生命周期问题:
• 如果argv
是一个std::vector
,并且在调用redisCommandArgv
之前被销毁或重新分配,那么argv.data()
指向的内存可能已经无效。
2.4 报错分析
2.4.1 确认变量作用域
检查zryMyRedisTool::cleanExpiredFields
函数中所有变量的作用域,确保在调用redisCommandArgv
时,所有变量仍然有效。
2.4.2 检查argv
和zsetKey
的生命周期
确保argv
和zsetKey
在调用redisCommandArgv
时仍然有效。可以通过以下方式解决:
• 将argv
和zsetKey
的作用域提升到整个函数。
• 确保argv
和zsetKey
在调用redisCommandArgv
之前不会被销毁或重新分配。
2.4.3 使用std::vector
的正确方式
如果argv
是一个std::vector
,确保在调用redisCommandArgv
时,argv
的生命周期仍然有效。可以使用std::vector
的data()
方法获取指针,但需要确保std::vector
不会被重新分配。
2.5 代码示例
2.5.1 错误代码示例
以下是可能导致问题的代码示例:
int zryMyRedisTool::cleanExpiredFields(const std::string &hashKey)
{
if (cleanup_sha.empty() && !loadCleanupScript())
{
return -1; // 脚本加载失败
}
const std::string zsetKey = hashKey + ":expires";
const time_t now = time(nullptr);
// argv 的生命周期可能在调用 redisCommandArgv 时已经结束
std::vector<const char *> argv = {
"EVALSHA",
cleanup_sha.c_str(),
"2", // KEYS 数量
zsetKey.c_str(), // 有序集合键 (KEYS[1])
hashKey.c_str(), // 哈希键 (KEYS[2])
std::to_string(now).c_str() // 当前时间戳 (ARGV[1])
};
redisReply *reply = (redisReply *)redisCommandArgv(context, argv.size(), argv.data(), nullptr);
if (!reply)
{
ZRY_LOG_ERROR("cleanExpiredFields failed: no reply");
return -1;
}
// 处理 NOSCRIPT 错误(脚本未加载)
if (reply->type == REDIS_REPLY_ERROR &&
std::strstr(reply->str, "NOSCRIPT") != nullptr)
{
freeReplyObject(reply);
cleanup_sha.clear(); // 重置 SHA
return cleanExpiredFields(hashKey); // 重试
}
// 处理正常响应
int cleaned = -1;
if (reply->type == REDIS_REPLY_INTEGER)
{
cleaned = reply->integer;
ZRY_LOG_INFO("Cleaned {} fields from {}", cleaned, hashKey);
}
else if (reply->type == REDIS_REPLY_ERROR)
{
ZRY_LOG_ERROR("Cleanup error: {}", reply->str);
}
freeReplyObject(reply);
return cleaned;
}
2.5.2 修复代码示例
以下是修复后的代码示例:
int zryMyRedisTool::cleanExpiredFields(const std::string &hashKey)
{
if (cleanup_sha.empty() && !loadCleanupScript())
{
return -1; // 脚本加载失败
}
std::string zsetKey = hashKey + ":expires"; // 确保 zsetKey 的生命周期
const time_t now = time(nullptr);
std::vector<const char *> argv = {
"EVALSHA",
cleanup_sha.c_str(),
"2", // KEYS 数量
zsetKey.c_str(), // 有序集合键 (KEYS[1])
hashKey.c_str(), // 哈希键 (KEYS[2])
std::to_string(now).c_str() // 当前时间戳 (ARGV[1])
};
redisReply *reply = (redisReply *)redisCommandArgv(context, argv.size(), argv.data(), nullptr);
if (!reply)
{
ZRY_LOG_ERROR("cleanExpiredFields failed: no reply");
return -1;
}
// 处理 NOSCRIPT 错误(脚本未加载)
if (reply->type == REDIS_REPLY_ERROR &&
std::strstr(reply->str, "NOSCRIPT") != nullptr)
{
freeReplyObject(reply);
cleanup_sha.clear(); // 重置 SHA
return cleanExpiredFields(hashKey); // 重试
}
// 处理正常响应
int cleaned = -1;
if (reply->type == REDIS_REPLY_INTEGER)
{
cleaned = reply->integer;
ZRY_LOG_INFO("Cleaned {} fields from {}", cleaned, hashKey);
}
else if (reply->type == REDIS_REPLY_ERROR)
{
ZRY_LOG_ERROR("Cleanup error: {}", reply->str);
}
freeReplyObject(reply);
return cleaned;
}
2.6 Mermaid 图表
2.7 其他注意事项
• MySQL 警告:
WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.
这是一个 MySQL 的警告,表明MYSQL_OPT_RECONNECT
已经被弃用,建议使用其他方式来处理重连逻辑。
• SQL 错误:
Incorrect datetime value: '' for column 'end_time' at row 1
这是一个 SQL 错误,表明在插入数据时,end_time
列的值为空字符串,而该列可能需要一个有效的日期时间值。需要检查代码中对end_time
的赋值逻辑,确保其值有效。
2.8 总结
通过确保argv
和zsetKey
的生命周期,可以解决stack-use-after-scope
的问题。同时,需要检查 MySQL 的重连逻辑和 SQL 插入语句的合法性,以避免其他潜在问题。