如何有效降低编码阶段的bug发生率?

2026-05-22 07:071阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1687个文字,预计阅读时间需要7分钟。

如何有效降低编码阶段的bug发生率?

前言:作为一名合格的程序员,不写bug是几乎不可能的。那么,如何花费最少的时间来修复bug呢?

1. 在编码阶段,借助一些静态分析工具可以事半功倍,减少代码中的bug。

2.静态分析工具可以帮助减少代码中的bug。

前言

作为一名合格的程序员,不写bug是不可能的。如何花费最少的时间来修复bug呢?

在编码阶段借助一些静态分析工具往往可以事半功倍,减少代码中的bug。

静态分析工具能够在代码未运行的情况下分析源代码,发现代码中的bug。在C/C++程序中,静态分析工具可以发现程序错误,如空指针取消引用、内存泄漏、被零除、整数溢出、越界访问、初始化前使用等。

编译器中的静态分析

编译器的目标是生成可执行文件,所以,他们并不关注静态代码分析。

但是,随着编译器的慢慢完善,在静态分析方面也做得越来越好。

比如,当我们编译代码时,有时候编译器会产生很多烦人的警告。大多数时候,这些警告并不会给程序造成影响。因此,很多人并不会关注这些警告。

不过,我们应该充分信任编译器。毕竟,没有人比编译器更了解这门语言。

因此,我们必须花一些时间来认真检查编译器产生的警告。这比起花费几个小时甚至几天去解一个bug代价要小的多。

例如,看下下面的代码,你觉得他会打印“ON” 还是 “OFF”呢?

#include <stdio.h> #define ON 0xFF #define OFF 0x00 void print_message(char status) { if (status == ON) printf("ON\n"); else printf("OFF\n"); } int main(int argc, const char *argv[]) { print_message(ON); return 0; }

$ gcc main.c -o main $ ./main OFF!

结果出人意料!我第一次也错误的认为这段代码会打印“ON”。

如果我们用Clang编译,又有什么结果呢?

Clang main.c -o main main.c:8:16: warning: comparison of constant 255 with expression of type 'char' is always false [-Wtautological-constant-out-of-range-compare] if (status == ON) ~~~~~~ ^ ~~ 1 warning generated.

Clang是一个优秀的静态分析器,能够分析代码中潜在的问题。对于上面的问题,GCC 在编译时加上-Wall 和-Wpedantic编译选项也可以分析出bug。

$ gcc main.c -o main -Wall -Wpedantic main.c: In function ‘main’: main.c:3:13: warning: overflow in implicit constant conversion [-Woverflow] #define ON 0xFF ^ main.c:16:19: note: in expansion of macro ‘ON’ print_message(ON); ^

不过,Clang和GCC的主要任务是编译代码,静态分析也并不是在每次编译时都需要,而且编译器在做静态分析时需要花费大量的时间。这就是为什么我们需要一个专门的静态代码分析工具。

Wikipedia(en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis)中提供了静态代码分析工具的列表。cppcheck是最好的开源静态分析工具之一。

如何有效降低编码阶段的bug发生率?

cppcheck简介

Cppcheck是一个针对C/C++代码的静态分析工具,专注于检测未定义的行为和危险的编码行为。比如空指针,除零,整数溢出,无效的移位操作,无效的转换,STL的无效用法,内存管理,空指针引用,越界检查,未初始化的变量,未使用或者重复的代码等。

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

安装Cppcheck

可以通过以下命令,在线安装Cppcheck。

sudo apt install cppcheck

也可以直接下载源代码,手动编译安装:

wget 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 --version Cppcheck 1.90 使用Cppcheck分析代码 例子1

下面,我们通过一个例子来介绍Cppcheck的使用方法。你能找出以下代码中的两个bug吗?

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

使用GCC编译代码,并没有报出任何警告和错误。

$ gcc -Wall -Wextra -Werror -Wpedantic main.c -o main $ ls main main

Clang分析出了其中的一个bug。

$ clang -Wall -Wextra -Werror -Wpedantic -Weverything main.c -o main main.c:8:9: error: variable 'result' is uninitialized when used here [-Werror,-Wuninitialized] result += buf[i]; ^~~~~~ main.c:4:15: note: initialize the variable 'result' to silence this warning int result; ^ = 0 1 error generated.

而cppcheck找出了全部的bug。

$ cppcheck main.c Checking main.c ... main.c:8:22: error: Array 'buf[10]' accessed at index 10, which is out of bounds. [arrayIndexOutOfBounds] result += buf[i]; ^ main.c:8:9: error: Uninitialized variable: result [uninitvar] result += buf[i]; ^ 例子2

我们用cppcheck 分析下Busybox看看有什么样的结果。

$ wget busybox.net/downloads/busybox-1.31.1.tar.bz2 $ tar xfv busybox-1.31.1.tar.bz2 $ cd busybox-1.31.1/ $ cppcheck . 2>&1 | tee cppcheck.log ... $ cat cppcheck.log | grep error | wc -l 146

Busybox的最新版本中有超过140个可能的bug(在我写这篇文章的时候)。有些错误可能是误报,不过有几个是可以分析下的。

$ cat cppcheck.log | grep "Uninitialized variable" archival/libarchive/bz/blocksort.c:1034:20: error: Uninitialized variable: origPtr [uninitvar] archival/libarchive/bz/compress.c:235:18: error: Uninitialized variable: ll_i [uninitvar] archival/libarchive/bz/compress.c:679:20: error: Uninitialized variable: origPtr [uninitvar] archival/libarchive/decompress_bunzip2.c:165:20: error: Uninitialized variable: runCnt [uninitvar] console-tools/loadfont.c:146:6: error: Uninitialized variable: height [uninitvar] ... $ cat cppcheck.log | grep "out of bounds" util-linux/fdisk_sgi.c:138:10: error: Array 'freelist[17]' accessed at index 17, which is out of bounds. [arrayIndexOutOfBounds] util-linux/fdisk_sgi.c:138:10: note: Array index out of bounds util-linux/fdisk_sgi.c:139:10: error: Array 'freelist[17]' accessed at index 17, which is out of bounds. [arrayIndexOutOfBounds] util-linux/fdisk_sgi.c:139:10: note: Array index out of bounds util-linux/volume_id/iso9660.c:114:15: error: Buffer is accessed out of bounds: hs->id [bufferAccessOutOfBounds] ... $ cat cppcheck.log | grep "Resource leak" scripts/kconfig/confdata.c:376:4: error: Resource leak: out [resourceLeak] cppcheck扩展插件

Cppcheck还可以通过使用正则表达式创建新的检查规则来扩展,甚至可以通过用Python编写的模块来扩展。

此外,还有针对Eclipse、Visual Studio、Code::Blocks、Sublime Text和QtCreator等几种流行开发工具的cppcheck插件。

vim编辑器 插件链接:github.com/vim-syntastic/syntastic

总结

静态代码分析有时候可能会产生误报,但是cppcheck很好的平衡了真实bug和误报的数量。因此,建议大家可以在个人的开发工具中集成cppcheck静态分析工具。虽然它并不会解决你所有的问题,但是,它肯定有助于提高你代码的质量,并且减少你花在修正bug上的时间。

标签:bug前言

本文共计1687个文字,预计阅读时间需要7分钟。

如何有效降低编码阶段的bug发生率?

前言:作为一名合格的程序员,不写bug是几乎不可能的。那么,如何花费最少的时间来修复bug呢?

1. 在编码阶段,借助一些静态分析工具可以事半功倍,减少代码中的bug。

2.静态分析工具可以帮助减少代码中的bug。

前言

作为一名合格的程序员,不写bug是不可能的。如何花费最少的时间来修复bug呢?

在编码阶段借助一些静态分析工具往往可以事半功倍,减少代码中的bug。

静态分析工具能够在代码未运行的情况下分析源代码,发现代码中的bug。在C/C++程序中,静态分析工具可以发现程序错误,如空指针取消引用、内存泄漏、被零除、整数溢出、越界访问、初始化前使用等。

编译器中的静态分析

编译器的目标是生成可执行文件,所以,他们并不关注静态代码分析。

但是,随着编译器的慢慢完善,在静态分析方面也做得越来越好。

比如,当我们编译代码时,有时候编译器会产生很多烦人的警告。大多数时候,这些警告并不会给程序造成影响。因此,很多人并不会关注这些警告。

不过,我们应该充分信任编译器。毕竟,没有人比编译器更了解这门语言。

因此,我们必须花一些时间来认真检查编译器产生的警告。这比起花费几个小时甚至几天去解一个bug代价要小的多。

例如,看下下面的代码,你觉得他会打印“ON” 还是 “OFF”呢?

#include <stdio.h> #define ON 0xFF #define OFF 0x00 void print_message(char status) { if (status == ON) printf("ON\n"); else printf("OFF\n"); } int main(int argc, const char *argv[]) { print_message(ON); return 0; }

$ gcc main.c -o main $ ./main OFF!

结果出人意料!我第一次也错误的认为这段代码会打印“ON”。

如果我们用Clang编译,又有什么结果呢?

Clang main.c -o main main.c:8:16: warning: comparison of constant 255 with expression of type 'char' is always false [-Wtautological-constant-out-of-range-compare] if (status == ON) ~~~~~~ ^ ~~ 1 warning generated.

Clang是一个优秀的静态分析器,能够分析代码中潜在的问题。对于上面的问题,GCC 在编译时加上-Wall 和-Wpedantic编译选项也可以分析出bug。

$ gcc main.c -o main -Wall -Wpedantic main.c: In function ‘main’: main.c:3:13: warning: overflow in implicit constant conversion [-Woverflow] #define ON 0xFF ^ main.c:16:19: note: in expansion of macro ‘ON’ print_message(ON); ^

不过,Clang和GCC的主要任务是编译代码,静态分析也并不是在每次编译时都需要,而且编译器在做静态分析时需要花费大量的时间。这就是为什么我们需要一个专门的静态代码分析工具。

Wikipedia(en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis)中提供了静态代码分析工具的列表。cppcheck是最好的开源静态分析工具之一。

如何有效降低编码阶段的bug发生率?

cppcheck简介

Cppcheck是一个针对C/C++代码的静态分析工具,专注于检测未定义的行为和危险的编码行为。比如空指针,除零,整数溢出,无效的移位操作,无效的转换,STL的无效用法,内存管理,空指针引用,越界检查,未初始化的变量,未使用或者重复的代码等。

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

安装Cppcheck

可以通过以下命令,在线安装Cppcheck。

sudo apt install cppcheck

也可以直接下载源代码,手动编译安装:

wget 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 --version Cppcheck 1.90 使用Cppcheck分析代码 例子1

下面,我们通过一个例子来介绍Cppcheck的使用方法。你能找出以下代码中的两个bug吗?

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

使用GCC编译代码,并没有报出任何警告和错误。

$ gcc -Wall -Wextra -Werror -Wpedantic main.c -o main $ ls main main

Clang分析出了其中的一个bug。

$ clang -Wall -Wextra -Werror -Wpedantic -Weverything main.c -o main main.c:8:9: error: variable 'result' is uninitialized when used here [-Werror,-Wuninitialized] result += buf[i]; ^~~~~~ main.c:4:15: note: initialize the variable 'result' to silence this warning int result; ^ = 0 1 error generated.

而cppcheck找出了全部的bug。

$ cppcheck main.c Checking main.c ... main.c:8:22: error: Array 'buf[10]' accessed at index 10, which is out of bounds. [arrayIndexOutOfBounds] result += buf[i]; ^ main.c:8:9: error: Uninitialized variable: result [uninitvar] result += buf[i]; ^ 例子2

我们用cppcheck 分析下Busybox看看有什么样的结果。

$ wget busybox.net/downloads/busybox-1.31.1.tar.bz2 $ tar xfv busybox-1.31.1.tar.bz2 $ cd busybox-1.31.1/ $ cppcheck . 2>&1 | tee cppcheck.log ... $ cat cppcheck.log | grep error | wc -l 146

Busybox的最新版本中有超过140个可能的bug(在我写这篇文章的时候)。有些错误可能是误报,不过有几个是可以分析下的。

$ cat cppcheck.log | grep "Uninitialized variable" archival/libarchive/bz/blocksort.c:1034:20: error: Uninitialized variable: origPtr [uninitvar] archival/libarchive/bz/compress.c:235:18: error: Uninitialized variable: ll_i [uninitvar] archival/libarchive/bz/compress.c:679:20: error: Uninitialized variable: origPtr [uninitvar] archival/libarchive/decompress_bunzip2.c:165:20: error: Uninitialized variable: runCnt [uninitvar] console-tools/loadfont.c:146:6: error: Uninitialized variable: height [uninitvar] ... $ cat cppcheck.log | grep "out of bounds" util-linux/fdisk_sgi.c:138:10: error: Array 'freelist[17]' accessed at index 17, which is out of bounds. [arrayIndexOutOfBounds] util-linux/fdisk_sgi.c:138:10: note: Array index out of bounds util-linux/fdisk_sgi.c:139:10: error: Array 'freelist[17]' accessed at index 17, which is out of bounds. [arrayIndexOutOfBounds] util-linux/fdisk_sgi.c:139:10: note: Array index out of bounds util-linux/volume_id/iso9660.c:114:15: error: Buffer is accessed out of bounds: hs->id [bufferAccessOutOfBounds] ... $ cat cppcheck.log | grep "Resource leak" scripts/kconfig/confdata.c:376:4: error: Resource leak: out [resourceLeak] cppcheck扩展插件

Cppcheck还可以通过使用正则表达式创建新的检查规则来扩展,甚至可以通过用Python编写的模块来扩展。

此外,还有针对Eclipse、Visual Studio、Code::Blocks、Sublime Text和QtCreator等几种流行开发工具的cppcheck插件。

vim编辑器 插件链接:github.com/vim-syntastic/syntastic

总结

静态代码分析有时候可能会产生误报,但是cppcheck很好的平衡了真实bug和误报的数量。因此,建议大家可以在个人的开发工具中集成cppcheck静态分析工具。虽然它并不会解决你所有的问题,但是,它肯定有助于提高你代码的质量,并且减少你花在修正bug上的时间。

标签:bug前言