c++开源项目:十行代码15个bug,你入坑了吗?

mu-ge mu-ge     2022-12-12     767

关键词:

又一年即将结束,是时候盘点一下开源项目中的 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:(’ ’ != c)。params.c 136.

很奇怪,对不对?让我们看看在另一个文件(charset.h)中其它奇怪的点:

技术图片
 

嗯,这确实很奇怪… 因此,如果变量 c 等于’ ’,那么看起来无害的函数 isspace? 会返回 false,从而因为短路逻辑而不执行第二部分的检查。而且如果 isspace? 执行,变量 c 将会等于 ‘’ 或’ ’,明显不会等于’ ’。

你可能会说,这个宏与 #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++编程知识的话!那么你很幸运~

点击进入C语言C++学习企鹅圈子

分享(源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

编程学习书籍:

技术图片
 

编程学习视频:

技术图片
 






















入坑了,公司居然没有统一的api返回格式?(代码片段)

点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识无侵入式统一返回JSON格式其实本没有没打算写这篇博客的,但还是要写一下写这篇博客的起因是因为,现在呆着的这家公司居然没有统一的AP... 查看详情

入坑了,公司居然没有统一的api返回格式?(代码片段)

点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识无侵入式统一返回JSON格式其实本没有没打算写这篇博客的,但还是要写一下写这篇博客的起因是因为,现在呆着的这家公司居然没有统一的AP... 查看详情

peaks加强版bzoj3551你被坑了吗?

...鬼混、乱整乱撞后艰难地AC了。但惋惜的是,大米饼一号代码其实更加简洁,但至今找不出BUG,我将它放在下面,也许有一天从远方来的另一个大米饼会拯救它。让我们一起念出这道题的关键字:Kurskal,LCA倍增,Kurskal重构树,df... 查看详情

阿里开源的15个顶级java项目!!!(代码片段)

CanalCanal[kə'næl]翻译过来是水道/管道/沟渠的意思,主要用于基于MySQL数据库增量日志解析,提供增量数据订阅和消费。Canal可以帮助我们实现MySQL和其他数据源比如Elasticsearch、Kafka、RocketMQ或者另外一台MySQL数据库之间... 查看详情

阿里开源的15个顶级java项目!!!(代码片段)

CanalCanal[kə'næl]翻译过来是水道/管道/沟渠的意思,主要用于基于MySQL数据库增量日志解析,提供增量数据订阅和消费。Canal可以帮助我们实现MySQL和其他数据源比如Elasticsearch、Kafka、RocketMQ或者另外一台MySQL数据库之间... 查看详情

github上最热门的11个java开源项目你会了吗

前言4月份GitHub上最热门的Java开源项目排行已经出炉啦,一起来看看吧!1JimuReport(地址见文末)这是一款免费的数据可视化工具,报表与大屏设计!类似于excel操作风格,在线拖拽完成报表设计!... 查看详情

一篇万字博文带你入坑爬虫这条不归路(你还在犹豫什么&抓紧上车)❤️熬夜整理&建议收藏❤️(代码片段)

👻最近,很多粉丝私信我问——爬虫到底是什么?学习爬虫到底该从何下手?👻😬其实,我想说的也是曾经的我身为小白的时候某些大牛对我说过的——很多时候我们都有一颗想要学习新知识的心... 查看详情

一篇万字博文带你入坑爬虫这条不归路(你还在犹豫什么&抓紧上车)❤️熬夜整理&建议收藏❤️(代码片段)

👻最近,很多粉丝私信我问——爬虫到底是什么?学习爬虫到底该从何下手?👻😬其实,我想说的也是曾经的我身为小白的时候某些大牛对我说过的——很多时候我们都有一颗想要学习新知识的心... 查看详情

1-stm32带你入坑系列(stm32介绍)

  由于自己的物联网开发板上的单片机是用的STM32,但是有些朋友没有用过,所以我将用这块开发板,带着大家入门STM32 先介绍一下STM32,我是在大三下学期的时候开始接触STM32,当时是想做一个小车,要用摄像头,所以学习了STM... 查看详情

新手学习单片机最常见的六大误区,你进坑了吗?

...学校考试要背以外,我到现在为止,做过几十个项目都是用c语言,没用汇编 查看详情

google的c++开源代码项目

Google的C++开源代码项目v8 - V8JavaScriptEngineV8是Google的开源JavaScript引擎。V8采用C++编写,可在谷歌浏览器(来自Google的开源浏览器)中使用。V8根据ECMA-262第三版中的说明使用ECMAScript,并在使用IA-32或ARM处理器的WindowsXP和Vista... 查看详情

这35个java代码优化细节,你用了吗

...米一多之后,鲸鱼就被喂饱了。代码优化也是一样,如果项目着眼于尽快无BUG上线,那么此时可以抓大放小,代码的 查看详情

图文并茂,带你入坑本地缓存caffeine(代码片段)

点击关注公众号,实用技术文章及时了解关于缓存的几种算法关于缓存的设计在架构领域有非常多种类型,常见的缓存算法有FIFO,LRU,LFU,以及现在比较常用的W-TinyLFU算法。FIFO算法这类算法通常会被应用于缓... 查看详情

15个优秀开源的springboot学习项目

SpringBoot算是目前Java领域最火的技术栈了,松哥年初出版的《SpringBoot+Vue全栈开发实战》迄今为止已经加印了8次,SpringBoot的受欢迎程度可见一斑。经常有人问松哥有没有推荐的SpringBoot学习资料?当然有!买松哥书就对了,哈哈... 查看详情

手把手带你入坑抓包神器mitmproxy

参考技术A你是否会对应用程序正在发出的请求感到好奇,以及它会返回什么响应,你是否曾经捕获过流量用它来研究某些东西是如何工作的,如果你有,那么mitmproxy这个工具你应该会很喜欢。mitmproxy是一个支持HTTP和HTTPS的抓包... 查看详情

开源项目中的 C++ 类设计模式

】开源项目中的C++类设计模式【英文标题】:C++classdesignpatternsinopensourceprojects【发布时间】:2011-02-2312:21:31【问题描述】:我最近开始学习设计模式。我已经了解了一些模式的基础知识。现在我想熟悉一些使用这些模式的真实代... 查看详情

一个关于项目管理者与程序猿之间的笑话

...间表,产品终于上市了。用户发现了137个新Bug。已经领了项目奖金的程序员不知跑到哪里去了。新组建的项目 查看详情

一个关于项目管理者与程序猿之间的笑话

在网上看见有一个笑话是这样的: 1.程序员写出自认为没有Bug的代码。 2.软件测试,发现了20个Bug。 3.程序员修改了10个Bug,并告诉测试组另外10个不是Bug。 4.测试组发现其中5个改动根本无法工作,同时又发现了15... 查看详情