C ++ 核心检查中的算术溢出检查
[原文发表地址]:Arithmetic overflow checks in C++ Core Check
[原文发表时间]:2018年2月31日
[作者]:Sunny Chatterjee
我们已经用Visual Studio 2017中的每个主要编译器更新对C ++代码分析工具集进行了改进。在预览版本15.6中包含一组算术溢出检查。 本文讨论这些检查以及为什么要在代码中启用它们。
如果您刚刚开始使用Visual Studio中的C ++代码分析,请详细了解此概述博客中的总体体验。
动机
作为C ++代码分析团队的一员,我们与整个公司的团队合作,通过更好的工具和语言支持来确定检测的漏洞类别。 最近,作为微软最安全敏感的代码库之一的安全审查的一部分,我们发现我们需要添加检查以检测常见的算术溢出类。
例如:
我们研究了C ++核心指南,看看在这个领域是否有特定的指导方针。
算术规则
- ES.100:不要混合有符号和无符号算术
- ES.101:使用无符号类型进行位操作
- ES.102:使用有符号类型的算术
- ES.103:不要溢出
- ES.104:不要下溢
- ES.105:不要被零除
- ES.106:不要通过使用无符号类型来避免负值
- ES.107:不要使用无符号的下标,更倾向于gsl :: index
准则指出,其中一些规则在实践中可能会很棘手。 因此,我们采取了一种方法,试图将这套准则与我们希望在实施中检测到的那些缺陷模式相交叉。
检查
以下是我们添加到C ++ Core Check for 15.6发行版中的一组算术检查:
- C26450 RESULT_OF_ARITHMETIC_OPERATION_PROVABLY_LOSSY [operator]操作在编译时导致溢出。使用更宽泛的类型。
这个警告表明算术运算在编译时可能是有损的。 当操作数都是编译时常量时,这可以被声明。 目前,我们检查这种溢出的左移,乘法,加法和减法操作。
在修正源代码中,左操作数被转换为宽泛的类型,以使算术运算的结果宽泛。
- C26451 RESULT_OF_ARITHMETIC_OPERATION_CAST_TO_LARGER_SIZE对[size1]字节值使用运算符[operator],然后将结果
此警告表示从整体推广规则和类型的结果大于通常执行算术而导致的不正确的行为。我们检测何时一个狭隘类型的整数值左移,相乘,相加或相减,并将该算术运算的结果转换为宽泛的类型值。 如果操作溢出了窄类型值,则数据丢失。 在算术运算之前,可以通过将值转换为宽泛的类型来防止这种损失。
在修正的源代码中,左操作数被转换为宽泛的类型,以使算术运算的结果宽泛。
- C26452 SHIFT_COUNT_NEGATIVE_OR_TOO_BIG左移计数为负数或大于或等于未定义行为的操作数大小。
此警告表示移位计数为负值或大于或等于正在移位的操作数的位数,导致未定义的行为。
在修正的源代码中,左操作数被转换为64位值,然后向左移位32位。
- C26453 LEFTSHIFT_NEGATIVE_SIGNED_NUMBER负号的左移是未定义的行为。
这个警告表明我们正在左移一个负符号的整数值,这是一个坏主意,并触发了实施定义的行为。
在修正的源代码中,位移操作使用正整数值
- C26454 RESULT_OF_ARITHMETIC_OPERATION_NEGATIVE_UNSIGNED [operator]运算结果超过0并在编译时产生大的无符号数。
此警告表明减法运算会产生一个被评定在无符号类型中的负值。 这会导致结果超过0并产生非常大的无符号数字,这可能会导致意外溢出。
在修正的源代码中,一个正值被分配给无符号结果。
结果
我们在假日期间在安全敏感的代码库中运行这些检查,并发现有趣的错误模式。 我在本篇博文的开头重新分享了看起来很可疑的示例模式,以及它们现在触发的代码分析警告。
警告C26451算术溢出:对4个字节的值使用运算符'*',然后将结果转换为8个字节的值。 在调用操作符'*'以避免溢出之前将值转换为更宽的类型。
警告C26454算术溢出:' - '操作在编译时产生负的无符号结果,导致溢出
反馈
我们希望您能亲自尝试这些检查。下载15.6版的预览版6,让我们知道你的代码库中是否有任何有趣的错误模式。
与往常一样,如果您对我们有任何意见或建议,请告诉我们。 我们可以通过以下评论,通过电子邮件(visualcpp@microsoft.com)与您联系,您可以通过产品中的帮助>报告问题或通过开发者社区提供反馈。 您还可以在Twitter(@VisualC)和Facebook(msftvisualcpp)上找到我们。