【经验分享】关于静态分析工具排查 Bug 的方法

文章目录

  • 编译器的静态分析
  • cppcheck
    • 安装 cppcheck
    • 运行 cppcheck

程序员的日常工作,不是摸鱼扯皮,就是在写 Bug。虽然这是一个梗,但也可以看出,程序员的日常一定绕不开 Bug。而花更少的时间修复软件中的 Bug,且不引入新的 Bug,最好的办法就是使用静态分析工具排查 Bug。

所谓的静态分析,顾名思义,是指在不运行程序的情况下对源代码进行检查,通过算法和模式识别来检测可能存在的错误、漏洞或不符合编码规范的地方。这种方法不仅可以帮助开发者在早期阶段发现 Bug,还能提高代码质量和安全性,减少后期调试的时间和成本。

但是在讨论静态分析工具之前,你知道编译器也进行静态代码分析吗?

编译器的静态分析

编译器的作用,就是生成可执行文件或二进制文件,因此,在默认情况下,编译器并不用于静态代码分析。但随着技术的发展和版本的迭代更新,编译在静态代码分析方面不断改进并变得更好,不同版本的编译器在编译同一个代码时,出现警告数量可能都不一样。

对很多初学者来说,编译器生成的警告非常烦人,并且大多数消息并不关键或不会对应用程序造成任何问题。其实我们应该信任编译器,因为有一件事是肯定的:没有人比编译器本身更了解语言、语法和语义。

那么编译器要怎么进行静态分析呢?

以下面的代码为例,我用不同的编译器进行编译并运行,

#include <stdio.h>#define ON  0xFF
#define OFF 0x00void print_message(char status)
{if (status == ON)printf("ON\n");elseprintf("OFF\n");
}int main()
{print_message(ON);return 0;
}

这段代码看起来没有任何问题,而且看起来运行后会打印 ON,而实际上却打印 OFF

以 GCC 编译编译运行,结果如下:

在这里插入图片描述

如果源代码是用 Clang 编译器编译,会立刻给我们一个警告:

在这里插入图片描述

[!WARNING]

这是警告的具体意思,是一个整型常数 255 和一个 char 类型的表达式真正进行比较,代码可能存在逻辑上的问题。

可见 Clang 不仅是一个编译器,也是一个非常不错的静态分析工具。当然,这类警告 GCC 也可以发现,不过需要在编译时,加上两个参数 -Wall-Wpedantic。如下图:

在这里插入图片描述

[!NOTE]

-Wall-Wpedantic 的作用是什么?

  1. -Wall 参数告诉 GCC 启用所有非默认的警告选项。这意味着 GCC 将会报告许多常见的编程错误,包括但不限于未使用的变量、可疑的类型转换、可能的除零错误、条件表达式中的常量等。-Wall 可以帮助开发者找到那些可能在编译时没有错误但在运行时会导致问题的代码缺陷。

    例如,以下是一些由 -Wall 开启的警告:

    • uninitialized: 使用未初始化的变量;
    • unused: 定义了但未使用的变量或函数;
    • conversion: 类型转换可能导致数据丢失;
    • pointer-sign: 指针比较中正负符号的差异;
    • format-security: 格式字符串的安全问题;
    • overflow: 数值运算溢出的风险。
  2. -Wpedantic 参数使 GCC 更加严格地遵守标准,它将警告所有不符合 C 或 C++ 标准的代码。这意味着任何与标准不完全一致的语法或行为都会被标记出来,即使这种行为在 GCC 中可能是默认允许的。

    -Wpedantic 主要关注的是标准一致性问题,比如:

    • 使用扩展的语法,如 GNU 特有的语法;

    • 不符合标准的声明或初始化;

    • 未在标准中明确规定的编译器行为;

    • 对于 C++,它还会警告关于 C++11 或更高版本标准中不再推荐的用法;

值得注意的是, -Wpedantic 可能会警告以下情况:

  • 使用 C99 的特性(如复合字面量)在 C89 模式下编译。
  • 在 C++ 中使用 C 风格的字符串或旧的初始化语法。
  • 使用了在标准中没有定义的行为,比如某些类型的隐式转换。

通常,为了最大程度地提高代码质量,开发者会同时使用 -Wall-Wpedantic。这有助于确保代码不仅避免了常见的编程错误,而且也遵循了语言标准,从而提高了代码的可读性和可移植性。

然而,值得注意的是,-Wpedantic 可能会产生大量警告,特别是在处理旧代码或使用了某些非标准但实用的 GNU 扩展时。因此,在实际应用中,开发者可能需要根据具体情况调整警告级别,以避免被过多的警告信息淹没。

由此可见,作为开发者,我们应该注意所有编译器警告。甚至我们需要能够生成更多警告的工具,那种可以分析源代码并发现语言的奇怪结构、潜在问题和不寻常用法的工具。

Clang 和 GCC 在静态分析方面还是比较出色的,但这不是它们的主要作用,这些警告是在编译过程中完成的简单检查的副产品而言。此外,静态代码分析需要大量时间,并且通常不需要每次编译。编译时间对于编译器来说非常重要。在检查代码质量和编译时间之间需要权衡。

正是如此,也促使了静态代码分析工具的产生,这类工具也称为 lint,其中一个开源的静态分析工具 cppcheck,也是本文的主角。

cppcheck

Cppcheck 是 C/C++ 代码的静态分析工具,它提供独特的代码分析来检测错误,并专注于检测未定义的行为危险的编码结构,其中包括以下几个方面的内容:

  • 野指针或悬空指针
  • 除以零
  • 整数溢出
  • 无效的位移操作数
  • 无效转换
  • STL 的无效使用
  • 内存管理
  • 空指针取消引用
  • 越界检查
  • 未初始化的变量
  • 写入常量数据
  • 未使用或重复的代码

Cppcheck 是一个开源项目,目前托管在 Sourceforge 和 GitHub 上,支持 GNU/Linux、Windows 和 Mac OS 操作系统。

安装 cppcheck

安装 cppcheck 的步骤可在 Cppcheck 官网可以找到。

也可以从 Linux 发行版包管理器获取 cppcheck,以 Ubuntu 系统为例,可以运行以下命令来安装 cppcheck:

sudo apt update
sudo apt install cppcheck

如果要使用最新的 cppcheck 版本,则需要下载源代码,编译并安装,过程如下:

wget https://github.com/danmar/cppcheck/archive/1.90.tar.gz
tar xfv 1.90.tar.gz
cd cppcheck-1.90/
make MATCHCOMPILER=yes FILESDIR=/usr/share/cppcheck HAVE_RULES=yes -j4
sudo make MATCHCOMPILER=yes FILESDIR=/usr/share/cppcheck HAVE_RULES=yes install

运行 cppcheck

以下面这段代码为例,代码作用为计算整数数组的所有元素的总和:

#include <stdio.h>int buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int calc(void)
{int result;int i;for (i = 0; i <= 10; i++)result += buf[i];return result;
}int main()
{calc();return 0;
}

这段代码其实有两处风险,但是 GCC 编译器(版本号为 11.4.0)无法找到这些风险:

在这里插入图片描述

即使加上了 -Wextra-Werror 两个参数,也找不到任何风险:

在这里插入图片描述

[!NOTE]

-Wextra-Werror 的作用是什么?

  1. -Wextra 标志开启了一系列额外的警告,这些警告超出了默认警告的范畴。该参数的目的是捕捉那些可能不易察觉的编程错误,帮助开发者避免未来可能遇到的运行时错误和维护问题。它包含了多个单独的警告标志,涵盖了可能被忽略或不常见的代码问题,包括但不限于以下警告:

    • 使用未初始化的变量;
    • 形参与实参的类型不匹配;
    • 赋值运算符可能被误解为等于运算符;
    • 可能的枚举值溢出;
    • 函数调用的返回值被忽视;
    • 以及其他潜在的代码错误和不良实践。
  2. -Werror 标志的作用是将所有警告视为错误。换句话说,当编译器遇到任何被 -W 标志开启的警告时,它将停止编译过程,就像遇到了一个真正的编译错误一样。这迫使开发者在编译通过之前必须解决所有的警告。

    -Werror 的主要优点是强制执行代码质量标准,确保没有潜在的编程问题遗留到最终的二进制文件中。这在团队开发环境中特别有用,可以确保所有代码都达到一致的高标准。

现在换 Clang 编译器进行编译,同样也无法找到这些风险:

在这里插入图片描述

Clang 编译器也可以使用与 GCC 相同的参数,如下命令:

clang -Wall -Wextra -Werror -Wpedantic main.c -o main

执行命令后,可以找到两个错误:

在这里插入图片描述

但是这两个错误其实是重复的,引起两个错误的原因都是变量 result 未初始化,如果给 result 初始化后,就不会出现这个错误,如下图:

在这里插入图片描述

把程序改回原来的代码,用 cppcheck 检查,结果可以找到这两个错误,如下图:

在这里插入图片描述

除了 Clang 找出来的 result 未初始化之外,cppcheck 还在 for 循环中找到了数组越界。

[!CAUTION]

calc 函数的 for 循环中,使用了 i <= 10 作为循环终止条件,然而数组 buf 的下标是从 0 到 9(共10个元素)。当程序尝试访问 buf[10] 时,这实际上是越界访问,因为 buf[10] 并不存在(数组最后一个元素是 buf[9])。

由此可见,编译器并不能完全充当静态分析工具,逻辑上的错误还是要靠专业的静态分析工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/378291.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bug:时间字段显示有问题

Bug&#xff1a;时间字段显示有问题 文章目录 Bug&#xff1a;时间字段显示有问题1、问题2、解决方法一&#xff1a;添加注解3、解决方法二&#xff1a;消息转换器自定义对象映射器配置消息转换器 1、问题 ​ 在后端传输时间给前端的时候&#xff0c;发现前端的时间显示有问题…

汽车开发阶段(OTS/VFF/PVS/OS/SOP)

OTS&#xff1a;即英语中的Off Tooling Sample&#xff0c;通常被称为工装样件。它指的是通过配套设备、工装夹具以及模具制造出来的样品&#xff0c;但并不强调生产的时间效率&#xff0c;主要用于验证产品的设计能力。 VFF&#xff1a;在德语中表示为Vorserien Freigabefahr…

太速科技-FMC207-基于FMC 两路QSFP+光纤收发子卡

FMC207-基于FMC 两路QSFP光纤收发子卡 一、板卡概述 本卡是一个FPGA夹层卡&#xff08;FMC&#xff09;模块&#xff0c;可提供高达2个QSFP / QSFP 模块接口&#xff0c;直接插入千兆位级收发器&#xff08;MGT&#xff09;的赛灵思FPGA。支持利用Spartan-6、Virtex-6、Kin…

eNsp公司管理的网络NAT策略搭建

实验拓扑图 实验需求&#xff1a; 7&#xff0c;办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 8&#xff0c;分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器 9&#xff0c;多出口环境基于带…

JavaWeb(四:Ajax与Json)

一、Ajax 1.定义 Ajax&#xff08;Asynchronous JavaScript And XML&#xff09;&#xff1a;异步的 JavaScript 和 XML AJAX 不是新的编程语言&#xff0c;指的是⼀种交互方式&#xff1a;异步加载。 客户端和服务器的数据交互更新在局部页面的技术&#xff0c;不需要刷新…

VUE:跨域配置代理服务器

//在vite.config。js中&#xff0c;同插件配置同级进行配置server:{proxy:{"/myrequest":{//代理域名&#xff0c;可自行修改target:"https://m.wzj.com/",//访问服务器的目标域名changeOrigin:true,//允许跨域configure:(proxy,options) > {proxy.on(&…

未知物材料成分配方检测分析

材料成分配方分析是一种通过分析材料的化学成分、结构和性质来确定其组成和配方的方法。这对于产品质量控制、新产品研发、工业问题解决和环保等领域具有重要意义。进行材料成分配方分析通常需要以下步骤&#xff1a; 1. 样品采集&#xff1a;采集需要分析的材料样品&#xff0…

从 Pandas 到 Polars 十八:数据科学 2025,对未来几年内数据科学领域发展的预测或展望

我在2021年底开始使用Polars和DuckDB。我立刻意识到这些库很快就会成为数据科学生态系统的核心。自那时起&#xff0c;这些库的受欢迎程度呈指数级增长。 在这篇文章中&#xff0c;我做出了一些关于未来几年数据科学领域的发展方向和原因的预测。 这篇文章旨在检验我的预测能力…

再谈有关JVM中的四种引用

1.强引用 强引用就是我们平时使用最多的那种引用&#xff0c;就比如以下的代码 //创建一个对象 Object obj new Object();//强引用 这个例子就是创建了一个对象并建立了强引用&#xff0c;强引用一般就是默认支持的当内存不足的时候&#xff0c;JVM开始垃圾回收&#xff0c…

【Linux系统编程】软硬链接和动静态库

一&#xff0c;硬链接 1-1&#xff0c;硬链接的认识 Linux下的硬链接本质是在指定的目录下&#xff0c;插入新的文件名和目标文件的眏射关系&#xff0c;并让inode的引用计数加一&#xff0c;这里我们通过 ls 指令可查看到文件详细信息种的硬链接数。这里可参考文件系统的文章…

Linux - 冯-诺依曼体系结构、初始操作系统

目录 冯•诺依曼体系 结构推导 内存提高效率的方法 数据的流动过程 体系结构相关知识 初始操作系统 定位 设计目的 操作系统之上之下分别有什么 管理精髓&#xff1a;先描述&#xff0c;再组织 冯•诺依曼体系 结构推导 计算机基本工作流程图大致如下&#xff1a; 输入设备&a…

Web3D:WebGL为什么在渲染性能上输给了WebGPU。

WebGL已经成为了web3D的标配&#xff0c;市面上有N多基于webGL的3D引擎&#xff0c;WebGPU作为挑战者&#xff0c;在渲染性能上确实改过webGL一头&#xff0c;由于起步较晚&#xff0c;想通过这个优势加持&#xff0c;赶上并超越webGL仍需时日。 贝格前端工场为大家分享一下这…

【微信小程序知识点】自定义构建npm

在实际开发中&#xff0c;随着项目的功能越来越多&#xff0c;项目越来越复杂&#xff0c;文件目录也变得很繁琐&#xff0c;为了方便进行项目的开发&#xff0c;开发人员通常会对目录结构进行优化调整&#xff0c;例如&#xff1a;将小程序源码放到miniprogram目录下。 &…

JuiceFS缓存特性

缓存 对于一个由对象存储和数据库组合驱动的文件系统&#xff0c;缓存是本地客户端与远端服务之间高效交互的重要纽带。读写的数据可以提前或者异步载入缓存&#xff0c;再由客户端在后台与远端服务交互执行异步上传或预取数据。相比直接与远端服务交互&#xff0c;采用缓存技…

SAP PP学习笔记28 - 生产订单的收货及品质管理

上一章讲了生产订单的很多概念&#xff0c;比如确认&#xff08;报工&#xff09;以及报工的各种形式&#xff0c;反冲&#xff0c;自动入库等。 SAP PP学习笔记27 - Confirmation(报工/确认&#xff09;(CO11&#xff0c;CO11N&#xff0c;CO15&#xff0c;CO12)&#xff0c;…

【算法】LRU缓存

难度&#xff1a;中等 题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;…

【HarmonyOS】关于鸿蒙消息推送的心得体会 (一)

【HarmonyOS】关于鸿蒙消息推送的心得体会&#xff08;一&#xff09; 前言 这几天调研了鸿蒙消息推送的实现方式&#xff0c;形成了开发设计方案&#xff0c;颇有体会&#xff0c;与各位分享。 虽然没做之前觉得很简单的小功能&#xff0c;貌似只需要和华为服务器通信&…

LDAPWordlistHarvester:基于LDAP数据的字典生成工具

关于LDAPWordlistHarvester LDAPWordlistHarvester是一款功能强大的字典列表生成工具&#xff0c;该工具可以根据LDAP中的详细信息生成字典列表文件&#xff0c;广大研究人员随后可以利用生成的字典文件测试目标域账号的非随机密码安全性。 工具特征 1、支持根据LDAP中的详细信…

高效运转!便携式果汁机必备霍尔板

文章目录 文章目录 前言 一、 直流电机原理 二、 通过霍尔传感器控制无刷直流电机 三、 霍尔在霍尔板上的位置 前言 今天给大家带来一款运用在果汁机上的霍尔板&#xff0c;饮料再好&#xff0c;终归是饮料&#xff0c;果汁再好喝&#xff0c;也不如自己亲自榨得健康。 生活水…

年化18.9%的创业板趋势策略,使用模块化策略模板重构(代码+数据)

原创文章第590篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 昨天咱们分享的文章&#xff1a;”以交易为生“&#xff0c;基础设施很重要。 传统backtrader写策略的步骤是如下&#xff1a; 1、定义因子&#xff0c;比如动量roc&#xff1a; …