又一年即将结束,是时候盘点一下开源项目了 Bug 了。2020 年度盘点可能需要一些时间。让我们先来看看这篇文章 2019 年开源 C/C 项目中遇到的一些最有趣的槽点。
No. 10. 我们么操作系统么操作系统?
V1040 也许拼写错误预定义宏名称。MINGW32_‘有点像’MINGW32__’。winapi.h 4112
MINGW32_ 宏的名字拼写错误(MINGW32 其实是声明MINGW32__)。拼写是正确的:
顺便说一句,这个 bug 不在文章中"CMake: the Case when the Project’s Quality is Unforgivable"它首次被描述为开源项目 V1040 诊断是第一次真正发现 bug(2019 年 8 月 19 日)。
https://www.viva64.com/en/b/0658/?ref=hackernoon.com
No. 9. 哪个先?
V502 可能性:操作符的工作方式与预期不一致。==操作符低。mir_parser.cpp 884
以下部分我们感兴趣:
'==与三元运算符相比,运算符的优先级 (?:) 高。因此,该条件表达式的求值顺序是错误的,相当于以下代码:
由于常量 OP_intrinsiccall 和 OP_intrinsiccallassigned 都是非 null 是的,这个条件会一直回归 true,这意味着 else 分支是无法访问的代码。
这个 bug 在文章"Checking the Ark Compiler Recently Made Open-Source by Huawei"中被提到。
https://www.viva64.com/en/b/0690/?ref=hackernoon.com
No. 8. 危险位运算符
V1046 在位运算符在位运算符&=不安全使用bool’和’int’类型。GSLMultiRootFinder.h 175
代码建议 SetFunctionList 函数遍历迭代器列表。如果至少有一个迭代器无效,则该函数将返回 false,否则就返回 true。
然而,SetFunctionList 函数对于有效的迭代器也会返回 false。让我们看看为什么。AddFunction 函数返回 fFunctions 列表中有效迭代器的数量。也就是说,添加非空迭代器会增加列表的大小:1、2、3、4,等等。 bug 生效地点:
ret &= AddFunction(*f);
因为这个函数一个个返回 int 类型值而非 bool 因此,对于偶数值,类型&=操作符也会返回 false,因为偶数的最低有效位始终设置为 0.这就是为什么一个小的 bug 会打破 SetFunctionsList 即使其参数有效,返回值。
如果你仔细阅读代码片段(你是认真的,对吗?),你可能已经发现它来自 ROOT 项目。是的,我们也发现了这个 bug:“Analyzing the Code of ROOT, Scientific Data Analysis Framework”。
https://www.viva64.com/en/b/0682/?ref=hackernoon.com
No. 7. 变量混淆
V1001[CWE-563] 'Mode变量被赋值,但直到函数结束才被使用。SIModeRegister.cpp 48
使用相同名称的函数参数和类别成员是非常危险的,因为你很可能会混淆它们。这就是这样。以下表达式毫无意义:
Mode&= Mask;
函数的参数变化后,该参数不会以任何形式使用。编程师可能想写的是:
这个 bug 在 LLVM 发现。我们有一个不时检查这个项目的传统。今年我们又来了 这个项目检查了一次。
No. 6. C 有自己的的规则
这个 bug 源于 C 规则并不总是遵循数学规则或常识。看看下面的代码片段,试着找出自己 bug 吧。
V709 发现的可疑比较:‘f0 == f1 == m_fractureBodies.size()。 ‘a == b == c这并不等于‘’a == b && b == c’。
这种条件表达式似乎在检查 f0 等于 f1,并且等于 m_fractureBodies 中元素的数量。这可能意味着检查 f0 和 f1 是否位于 m_fractureBodies 数组的末尾,因为它们都包含被子 findLinearSearch() 方法中发现的对象。但实际上,这种条件表达式检查 f0 是否等于 f1,然后检查 m_fractureBodies.size() 是否等于 f0 == f1 表达结果。也就是说,这里的第三个运算数是 0 或 1。
这是一个好 bug!而且,幸运的是,这个 bug 非常罕见。到目前为止,我们只是 3 我见过这个开源项目 bug,有趣的是,这个 3 个项目都是游戏引擎。这不是 Bullet 唯一发现的 bug;最有趣的一些 bug 在文章"PVS-Studio Looked into the Red Dead Redemption’s Bullet Engine"有描述。
https://www.viva64.com/en/b/0647/?ref=hackernoon.com
No. 5. 什么是行末尾?
这个 bug 如果你知道细节,很容易发现。
V739 EOF 不应该和一个不应该和一个char比较类型值。ch’应该是’int’类型。json.cpp 762
这是你很难找到的一些 bugs 如果你不知道 EOF 是被定义为 -1 的话。因此,如果你试图将其与带有标志的字符类型变量进行比较,条件表达式的结果几乎总是 false。唯一的例外是编码 0xFF(255) 的字符。当与 EOF 比较时,这个字符会变成 -1.因此,这种条件表达式的结果将被视为 true。
这几年很多 bugs 中,前 10 所有的名字都是在计算机游戏软件中发现的:引擎或开源游戏。你可能已经猜到了,这个 bug 游戏领域也有更多的错误。"Cataclysm Dark Days Ahead: Static Analysis and Roguelike Games"文章中有描述。
https://www.viva64.com/en/b/0628/?ref=hackernoon.com
No. 4. 常量 Pi
V624 对于’3.141592538常量可能打印错误。考虑使用 <math.h> 中的 M_PI 常量。PhysicsClientC_API.cpp 4109
在 Pi 数字 (3,141592653…) 有一个小的打印错误:第一 7 小数位数字6丢失。
一个不正确的百万分之一的小数位很难造成任何明显的损害,但最好使用库中现有的常以保证其正确性。Pi 数字由头文件 math.h 中的 M_PI 常量表示。
你可能在文章中"PVS-Studio Looked into the Red Dead Redemption’s Bullet Engine"读过这个 bug,其中排名第一 6 位果你还没读过,这次不要错过。
https://www.viva64.com/en/b/0647/?ref=hackernoon.com
No. 3. 异常难以捉摸
V702std::exception(和类似)中的类应该是public如果没有指定关键字,编译器默认为‘private’的)。CalcManager CalcException.h 4
来自分析器的检测 std::exception 使用了一个类 private 修饰符(如未指定,默认使用 private)。这个代码的问题是试图捕获一个通用代码 std::exception 这个程序会错过 CalcException 类型异常。这种行为源于 private 继承禁止隐式类型转换。
你当然不想看到你的程序的程序而看到你的程序 public 修改符号并崩溃。顺便说一句,我打赌你一生中至少用过一次这个应用程序,因为它旧的 Windows Calculator,几年前我们也检查过这个应用程序。
No. 2. 未闭合的 HTML 标签
V735 可能是不正确的 HTML。碰到"关闭标签时,预期是" 标签。book.cpp 127
因为它经常发生,C/C 源代码本身没有太多的解释,所以让我们来看看上述代码片段生成的预处理代码:
分析器发现了一个未闭合的分析器 div 这里有很多标签 html 代码片段,因此作者需要修改代码。
我们很惊讶我们能诊断出这种类型 bugs 我第一次看这一点时,印象也非常深刻。因此,是的,我们确实知道一些关于分析 html 代码的知识。不过,只在 C++ 代码中才行。:)
不仅这个 bug 被排在第二位,这也是我们的前 10 榜单中的第二个计算器。可以阅读"Following in the Footsteps of Calculators: SpeedCrunch"这篇文章,来看看我们在这个项目发现的其它 bugs。
https://www.viva64.com/en/b/0618/?ref=hackernoon.com
No. 1. 难以捉摸的标准函数
这个 bug 位于第一位,是一种非常奇怪的 bug,能够成功通过代码评审。
你自己试试发现这个 bug:
现在让我们看看分析器怎么说:
V560 部分条件表达式总是 true:(’\n’ != c)。params.c 136.
很奇怪,对不对?让我们看看在另一个文件(charset.h)中其它奇怪的点:
嗯,这确实很奇怪… 因此,如果变量 c 等于’\n’,那么看起来无害的函数 isspace© 会返回 false,从而因为短路逻辑而不执行第二部分的检查。而且如果 isspace© 执行,变量 c 将会等于 ‘’ 或’\t’,明显不会等于’\n’。
你可能会说,这个宏与 #define true false 类似,像这样的代码永远不能通过一个代码评审。但是这个特殊的代码片段确实通过了代码评审——而且还在代码库中等待被发现。
有关这个 bug 的更详细的评论,请查看文章"Wanna Play a Detective? Find the Bug in a Function from Midnight Commander"。
https://www.viva64.com/en/b/0610/
结 论
我们发现的这些 Bug 都是一些常见的复制 - 粘贴错误、不准确的常量、未闭合的标签以及许多其它缺陷。但是我们的分析器正在不断演进和 学习 来诊断越来越多类型的问题,因此我们肯定不会放慢脚步,并且会像以前一样定期发布关于项目中发现的 bugs 的新文章。
作者介绍:
PVS-Studio 致力于寻找 C、C++、C#、Java 在 Windows、Linux 和 macOS 上的 bugs。
另外本人是一名C/C++的爱好者,如果你想更好的提升你的编程能力,好好学习C/C++编程知识的话!那么你很幸运~
【】
分享(源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
编程学习书籍:
编程学习视频: