中文
注册
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助
鲲鹏小智

C/C++进程异常结束

定位思路

C/C++进程未按设计要求进行执行,出现异常结束的情况。定位思路如图1所示。
图1 C/C++进程异常结束问题定位思路
  1. 确认问题现象,是C/C++程序异常结束。
  2. 在修改编译脚本或者打开调试宏开关,重新编译可调试版程序。
  3. 打开coredump开关,以便后续重新异常结束能生成coredump文件。
  4. 运行程序,当程序异常结束时,在指定路径确认生成coredump文件。
  5. 使用GDB调试coredump文件,定位异常结束原因。
  6. 修改相关代码,重新编译进行验证。
    • 若问题解决,则确认修改,合入原代码。
    • 若问题未解决,重新运行生成coredump文件进行定位,若缺乏定位信息,可在代码中增加定位信息,重新编译运行。

案例:内存越界导致程序异常

问题现象:

某软件在服务器上运行出现异常退出问题。

定位过程:

  1. 使用top查看,确认相关进程已结束,确认问题是异常退出。
  2. 在makefile里增加-g编译选项,重新编译代码。
  3. 在操作系统打开core文件生成功能,设置core文件生成路径。
    1
    2
    ulimit -c unlimited
    echo "/home/core.%e.%p.%t" > /proc/sys/kernel/core_pattern
    
  4. 运行程序,程序异常结束后,在指定路径生成coredump文件core.dsa_sign_multi.xxx.xxx。
  5. 通过GDB调试coredump文件,进入调试界面,如下图所示。
    1
    gdb dsa_sign_multi core.dsa_sign_multi.xxx.xxx
    

  6. 通过info threads命令查看该进程的线程信息。

  7. 通过thread命令切换想要查询的线程号,通过bt命令查看线程堆栈。
    1
    2
    thread $ID
    bt
    

  8. 分析堆栈信息,定位到问题在于调用OpenSSL相关库,但由于系统使用的OpenSSL非调试版本,无法看到OpenSSL的堆栈信息。需要重新编译OpenSSL可调试版本。
  9. 重新编译可调试版本的OpenSSL,并让程序链接,重新运行程序,生成新的coredump文件,并调试,查看相关堆栈信息。

  10. 查看报错堆栈相关参数信息。
    1
    2
    info locals
    f xx
    

  11. 查看相关代码源码实现。

    “MD_Update()”函数是对“EVP_DigestUpdate()”函数的宏别名。

  12. 找到“EVP_DigestUpdate()”函数实现:

    该函数的第三个参数应该传入无符号整型。

    第三个参数是(MD_DIGEST_LENGTH / 2 – k),而k由(st_idx + MD_DIGEST_LENGTH / 2)计算得到。而MD_DIGEST_LENGTH是常量,st_idx是变量。

  13. 查看代码实现,分析st_idx是由全局变量state_index拷贝到st_idx,随后对state_index累加并转换防止超出STATE_SIZE。

  14. 正常的流程中st_idx并不会超出STATE_SIZE,但是在多线程环境下,有低概率出现state_index累加之后未来得及转换就被其他线程使用,导致超出STATE_SIZE,这导致(MD_DIGEST_LENGTH / 2 – k)计算结果为负。传入EVP_DigestUpdate()后,被按照无符号数进行计算,导致越界,触发coredump问题。
  15. 对静态变量state_index加锁保护,重新编译代码,验证,未出现问题,确认修改合入,问题解决。
搜索结果
找到“0”个结果

当前产品无相关内容

未找到相关内容,请尝试其他搜索词