程序运行报错分析文档

bash 复制代码
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 报错原因

• 变量作用域问题:

argvzsetKey的作用域可能在调用redisCommandArgv时已经结束。

std::vector的生命周期问题,导致argv.data()指向的内存无效。

std::vector的生命周期问题:

• 如果argv是一个std::vector,并且在调用redisCommandArgv之前被销毁或重新分配,那么argv.data()指向的内存可能已经无效。

2.4 报错分析

2.4.1 确认变量作用域

检查zryMyRedisTool::cleanExpiredFields函数中所有变量的作用域,确保在调用redisCommandArgv时,所有变量仍然有效。

2.4.2 检查argvzsetKey的生命周期

确保argvzsetKey在调用redisCommandArgv时仍然有效。可以通过以下方式解决:

• 将argvzsetKey的作用域提升到整个函数。

• 确保argvzsetKey在调用redisCommandArgv之前不会被销毁或重新分配。

2.4.3 使用std::vector的正确方式

如果argv是一个std::vector,确保在调用redisCommandArgv时,argv的生命周期仍然有效。可以使用std::vectordata()方法获取指针,但需要确保std::vector不会被重新分配。

2.5 代码示例

2.5.1 错误代码示例

以下是可能导致问题的代码示例:

cpp 复制代码
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 修复代码示例

以下是修复后的代码示例:

cpp 复制代码
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 图表
为空 失败 成功 不为空 失败 成功 NOSCRIPT 错误 无错误 程序启动 运行 cleanExpiredFields 函数 检查 cleanup_sha 是否为空 加载清理脚本 检查加载是否成功 返回 -1 继续执行 构造 zsetKey 和 argv 调用 redisCommandArgv 检查回复是否成功 记录错误并返回 -1 处理 NOSCRIPT 错误 重置 SHA 并重试 处理正常响应 记录清理结果 释放 reply 对象 返回清理结果

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 总结

通过确保argvzsetKey的生命周期,可以解决stack-use-after-scope的问题。同时,需要检查 MySQL 的重连逻辑和 SQL 插入语句的合法性,以避免其他潜在问题。

相关推荐
liuzhangfeiabc1 小时前
[luogu12541] [APIO2025] Hack! - 交互 - 构造 - 数论 - BSGS
c++·算法·题解
学习使我变快乐1 小时前
C++:迭代器
开发语言·c++·windows
好想有猫猫1 小时前
【Redis】List 列表
数据库·c++·redis·分布式·缓存·list
superior tigre3 小时前
C++学习:六个月从基础到就业——C++11/14:其他语言特性
c++·学习
天堂的恶魔9463 小时前
C++ - 仿 RabbitMQ 实现消息队列(2)(Protobuf 和 Muduo 初识)
c++·rabbitmq·ruby
休息一下接着来4 小时前
进程间通信(IPC)常用方式对比
linux·c++·进程间通讯
虾球xz4 小时前
游戏引擎学习第288天:继续完成Brains
c++·学习·游戏引擎
John_ToDebug4 小时前
Chromium 浏览器核心生命周期剖析:从 BrowserProcess 全局管理到 Browser 窗口实例
c++·chrome·性能优化
June`4 小时前
专题五:floodfill算法(图像渲染深度优先遍历解析与实现)
c++·算法·leetcode·深度优先·剪枝·floodfill
流星白龙4 小时前
【C++算法】70.队列+宽搜_N 叉树的层序遍历
开发语言·c++·算法