当前位置: 首页 > news >正文

C++(Qt)软件调试---bug排查记录(36)

C++(Qt)软件调试—bug排查记录(36)


文章目录

  • C++(Qt)软件调试---bug排查记录(36)
    • @[toc]
    • 1 无返回值函数风险
    • 2 空指针调用隐患
    • 3 Debug/Release差异
    • 4 ARM架构char符号问题
    • 5 linux下找不到动态库

更多精彩内容
👉内容导航 👈
👉C++软件调试 👈

1 无返回值函数风险

  • 如果一个函数的返回值为void,则编译器会自动插入一个默认return;

  • 如果非void的函数没有写return,有些版本的编译器会默认插入一个ret(例如gcc7.3,高版本gcc会插入ud2),不过这个代码还是不安全的。

  • 如果一个函数的返回值不为void,但是忘记写return语句了,会破坏栈帧的出栈,导致未定义异常,可能会软件崩溃,也可能不会崩溃,调用者会试图从栈上的某个位置读取返回值。由于这个位置没有被正确设置,读取的内容将是随机的数据,这可能导致程序继续运行但行为异常;

  • Release版本与Debug版本的差异:在Debug版本中,由于内存受到保护,即使函数没有return语句,也可能不会立即导致程序崩溃。但在Release版本中,由于所有保护都被移除,访问错误内存或寄存器值很可能导致程序异常退出或崩溃。

  • 使用基本数据类型有可能不会导致程序崩溃。

  • 例如:

int fun1()
{int a = 123;
}
QByteArray fun2()
{QByteArray arr("123");
}
int main()
{fun1();fun2();return 0;
}
  • 并且这种情况导致的程序崩溃使用调试工具很难定位,定位的位置非常随机。

  • 不过要视编译器而定,有些编译器会编译报错,例如MSVC,有些不会,例如gcc默认只是会报警告-Wreturn-type

  • gcc可以通过-Werror=return-type选项将警告设置为错误信息,防止忽略;gcc编译选项

  • 或者使用MSVC编译器编译程序,也可以检测出未写return的错误。

  • QMake可以通过下面配置将缺失返回值警告设置为错误。

    QMAKE_CC += -Werror=return-type
    QMAKE_CXX += -Werror=return-type
    
  • 如下图所示,如果非void返回值函数没有写return语句,则在函数汇编中缺失popret指令;

    • pop 通常用于恢复先前保存的寄存器值(如 ebp 或者 rbp 在 x86 架构上),或者弹出参数等。如果没有执行 pop 操作,那么这些值将不会被正确地恢复,这可能会导致后续函数调用或程序逻辑出现问题。
    • 当函数调用发生时,返回地址会被压入栈中。如果函数结束时没有使用 ret 来处理这个返回地址,栈指针将指向错误的位置,破坏栈的结构,影响后续的函数调用和返回操作。
    • 缺少正确的 popret 指令使得调试更加复杂,因为正常的调用堆栈信息不再可靠。

在这里插入图片描述


2 空指针调用隐患

  • 当一个对象为空指针或者野指针时如果调用成员函数,可能会出现未定义异常导致崩溃,也可能不会崩溃;
  • 如果调用的成员函数没有使用this指针写入数据,则不会导致崩溃;
    • 情况1:没有使用到任何成员变量;
    • 情况2:调用的是static成员函数;
    • 情况3:只是读取成员变量,没有写入成员变量。
  • 这种不崩溃是危险的
    • 不可预测性:行为依赖于编译器、平台和运行时状态
    • 隐蔽性:错误可能在生产环境中突然出现
    • 调试困难:问题表现不稳定,难以复现
#include <iostream>
using namespace std;
class A {
public :void f(int x) {int a = x;// m_a = 123;   // 崩溃for(int i = 0; i < x; i++){cout << i << endl;}cout << a <<" " << &m_a <<" "<<this << endl;}
private:int m_a;
};int main() {A* a ;a -> f(10);a->f(2);return 0;
}

3 Debug/Release差异

Debug模式下通常会有更多的内存保护机制,这有助于捕获潜在的内存错误。

这些保护机制在Release模式下可能被禁用或简化,从而导致某些问题在Debug模式下不明显但在Release模式下暴露出来。具体来说:

  • 内存初始化

    • Debug模式下,编译器可能会自动将未初始化的变量设置为特定值(如0或特殊标记值),以帮助检测未初始化变量的使用。
    • Release模式下,未初始化的变量保持未初始化状态,可能导致不可预测的行为。
  • 边界检查

    • Debug模式下,可能会启用额外的数组和指针边界检查,防止越界访问。
    • Release模式下,这些检查通常被移除以提高性能,因此越界访问可能导致崩溃或未定义行为。
  • 堆栈保护

    • Debug模式下,堆栈可能会有更多的保护措施,例如填充“安全”值来检测堆栈溢出。
    • Release模式下,这些保护措施可能被移除或简化。
  • 调试信息

    • Debug模式下,程序会包含更多的调试信息和符号表,便于调试工具(如GDB、Visual Studio Debugger)进行更详细的分析。
    • Release模式下,这些调试信息通常被移除,导致难以通过调试工具捕捉到问题。

解决方法

  1. 使用静态分析工具

    • 使用静态分析工具(如Clang Static Analyzer、Cppcheck)来检测代码中的潜在问题。
  2. 启用运行时检查

    • 在Release模式下启用运行时检查工具,如AddressSanitizer、Valgrind等,可以帮助检测内存错误。
  3. 确保一致的初始化

    • 确保所有变量在使用前都已正确初始化,避免依赖Debug模式下的默认初始化行为。
  4. 检查内存分配和释放

    • 检查动态内存分配和释放是否正确,确保没有内存泄漏或双重释放的问题。
  5. 审查多线程代码

    • 如果程序涉及多线程,确保线程同步机制正确无误,避免竞争条件和死锁。
  6. 对比宏定义

    • 检查Debug和Release模式下的宏定义差异,确保两种模式下的行为一致,特别是与内存管理相关的宏定义。

4 ARM架构char符号问题

  • 在vs编译器、x86架构linux中的gcc编译器ux中的gcc编译器都是把char定义为signed char;

  • arm-linux-gcc把char定义为unsigned char;

  • 所以直接使用char有移植性问题,例如在x86架构中开发的程序,在arm架构系统(例如国产银河麒麟、树莓派、Android等)中可能就会出现问题,并且这种情况很隐蔽,比较难排查;

  • 例如在cppreference中的定义:

    在这里插入图片描述

  • 解决办法:

    1. 在编译时加上选项-fsigned-char
    2. 不使用char,改成使用int8_t或者qint8;

5 linux下找不到动态库

  1. 使用ldd命令查看可执行程序或者动态库的链接路径,是否找得到动态库;

  2. 使用下面命令查看、修改动态库链接路径

    patchelf --set-rpath '$ORIGIN/lib/' ./RadarServer     # 设置程序动态库链接路径
    patchelf --print-rpath ./RadarServer   # 打印链接路径
    



文章转载自:

http://XxNqAqXF.qbdsx.cn
http://eaXr1zBz.qbdsx.cn
http://xkklDMG2.qbdsx.cn
http://jLI3PkYh.qbdsx.cn
http://GCdvfXFS.qbdsx.cn
http://xrNrHiJN.qbdsx.cn
http://VtverZ6L.qbdsx.cn
http://GpNzWfmi.qbdsx.cn
http://Ko7nXxrY.qbdsx.cn
http://1Mhb1fW0.qbdsx.cn
http://nUjiHhOT.qbdsx.cn
http://PcmW3uXo.qbdsx.cn
http://Y6no0c9T.qbdsx.cn
http://nJLX0Rv2.qbdsx.cn
http://Rw67q5lx.qbdsx.cn
http://JsgCEKbH.qbdsx.cn
http://HwuoF9Gs.qbdsx.cn
http://sA1ThEmG.qbdsx.cn
http://CehfkhKJ.qbdsx.cn
http://JGNLH6VC.qbdsx.cn
http://xYeXjGAK.qbdsx.cn
http://kswHcZXF.qbdsx.cn
http://Sm21Z0eD.qbdsx.cn
http://y2pfYXZX.qbdsx.cn
http://uPb7E8Bu.qbdsx.cn
http://BJHVObD4.qbdsx.cn
http://Gap9JfH0.qbdsx.cn
http://iqDk6lqT.qbdsx.cn
http://YBTnS0Yf.qbdsx.cn
http://Lxb5WtDf.qbdsx.cn
http://www.dtcms.com/a/368367.html

相关文章:

  • yolov8部署在一台无显卡的电脑上,实时性强方案
  • Alibaba Cloud Linux 3 安装Docker
  • SQL面试题及详细答案150道(61-80) --- 多表连接查询篇
  • 详细解读Docker
  • 【OJ】C++ vector类OJ题
  • 【数据库】MySQL 数据库创建存储过程及使用场景详解
  • Ubuntu22.04-ROS2下navgation2编译到运行
  • OpenLayers常用控件 -- 章节四:图层控制与切换教程
  • [ubuntu][C++]onnxruntime安装cpu版本后测试代码
  • 一个专为地图制图和数据可视化设计的在线配色网站,可以助你制作漂亮的地图!
  • 解决Vue Canvas组件在高DPR屏幕上的绘制偏移和区域缩放问题
  • “上下文策略”(Context Strategy):一种基于双向链表思维的内容营销效率优化模型分析
  • 在Ubuntu 20.04的服务器上查找的服务器的IP地址
  • 用 Cursor AI 快速开发你的第一个编程小程序
  • 自动化运维-ansible中对roles的创建与使用
  • 《Ceph集群数据同步异常的根因突破与恢复实践》
  • 从零开始的云计算生活——第五十九天,基于Jenkins自动打包并部署Tomcat环境
  • 串口通信的学习
  • 企业为何仍困在“数据孤岛”?——从iPaaS重构信息流的实践路径
  • MySQL 主从复制详解:部署与进阶配置
  • 一笔成形,秒绘标准图!Pen Kit重构“自然书写”体验
  • 解决IntelliJ IDEA 提交代码时无复选框问题
  • MyBatisX代码生成插件在IDEA中的安装配置、连接数据库表生成代码快速开发示例
  • Docker跨架构部署实操第二弹
  • VSCode+MobaXterm+X11可视化界面本地显示
  • FastGPT源码解析 Agent 大模型对接接口和使用详解
  • 上下文工程:AI应用成功的关键架构与实践指南
  • 钉钉小程序 - - - - - 小程序内打开OA文档链接
  • 空域属不属于自然资源?(GPT5)
  • RK3506:赋能多场景智能硬件的核心芯片