没有有用且可靠的方法来检测C/C ++中的整数溢出?[英] No useful and reliable way to detect integer overflow in C/C++?

本文是小编为大家收集整理的关于没有有用且可靠的方法来检测C/C ++中的整数溢出?的处理方法,想解了没有有用且可靠的方法来检测C/C ++中的整数溢出?的问题怎么解决?没有有用且可靠的方法来检测C/C ++中的整数溢出?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

不,这不是如何检测整数溢出?.问题是相同的,但问题是不同的.


GCC编译器可以优化溢出检查(使用-O2),例如:

int a, b;
b = abs(a);                     // will overflow if a = 0x80000000
if (b < 0) printf("overflow");  // optimized away

海湾合作委员会人认为这不是错误.根据C标准,溢出是未定义的行为,该标准允许编译器做任何事情.显然,任何东西包括假设溢出永远不会发生.不幸的是,这允许编译器优化溢出检查.

在最近的 cert paper .本文建议在添加两个整数之前做类似的事情:

if ( ((si1^si2) | (((si1^(~(si1^si2) & INT_MIN)) + si2)^si2)) >= 0) { 
  /* handle error condition */
} else {
  sum = si1 + si2;
}

显然,当您想确保结果有效时,您必须在每次 +, - , *和/和其他操作之前进行类似的操作.例如,如果您要确保数组索引不是界限.这是如此麻烦,几乎没有人这样做.至少我从未见过有系统地执行此操作的C/C ++程序.

现在,这是一个基本问题:

  • 在访问数组之前检查数组索引很有用,但不可靠.

  • 使用CERT方法检查一系列计算中的每个操作是可靠但无用的.

  • 结论:没有有用且可靠的方法来检查C/C ++中的溢出!

我拒绝相信这是在编写标准时打算的.

我知道有某些命令行选项可以解决问题,但这并没有改变我们对标准或当前解释有根本问题的事实.

现在我的问题是: 海湾合作委员会的人们在允许他们优化溢出检查时对"不确定行为"的解释太远了,或者C/C ++标准是否损坏?

添加注: 抱歉,您可能已经误解了我的问题.我不是在问如何解决问题 - 已经回答其他地方" .我问一个关于C标准的更根本的问题.如果没有有用且可靠的检查溢出的方式,那么语言本身是可疑的.例如,如果我在界限检查中进行安全的数组课程,那么我应该是安全的,但是如果可以优化界限检查,则我不是.

如果标准允许这种情况发生,则标准需要修订或对标准需求的解释进行修订.

添加注2: 这里的人们似乎不愿讨论"不确定行为"的可疑概念. C99标准列出191种不同类型的未定义行为的事实( link )是一个指示马虎标准.

许多程序员很容易接受以下声明:"未定义行为"赋予执行任何操作的许可,包括格式化硬盘.我认为标准将整数溢出到与外部阵列范围编写相同的危险类别中是一个问题.

为什么这两种"未定义的行为"不同?因为:

  • 许多程序都依赖整数溢出是良性的,但是很少有程序在您不知道那里的内容时依赖于外部阵列界限.

  • 在阵列界外写作实际上 可以做一些像格式化硬盘一样糟糕的事情(至少在像DOS这样的未保护的OS中),并且大多数程序员知道这很危险.

  • 当您将整数溢出到危险的" Anythy Goes"类别中时,它允许编译器做任何事情,包括撒谎(在优化溢出检查的情况下)撒谎)

  • 可以通过调试器找到一个错误,例如在阵列范围外部范围,但是优化溢出检查的错误不能,因为调试时通常会关闭优化.

  • 在整数溢出的情况下,GCC编译器显然避免了"任何事物"策略.在许多情况下,它避免优化例如除非可以验证溢出是不可能的,否则循环是不可能的.由于某种原因,海湾合作委员会的人已经意识到,如果他们遵循"一切顺利"政策,我们将遇到太多错误,但是他们对优化溢出检查的问题有不同的态度.

也许这不是讨论此类哲学问题的正确地方.至少,这里的大多数答案是关注点.有一个更好的地方讨论吗?

推荐答案

GCC开发人员在这里完全正确.当标准表明行为不确定时,这完全意味着编译器上有 的要求.

作为一个有效的程序,无法执行引起UB的任何事情(因为那将不再有效),因此编译器可以很好地假设UB不会发生.如果仍然这样做,编译器的任何事情都可以.

对于您在溢出方面的问题,一种解决方案是考虑应处理的范围.例如,当平衡我的银行帐户时,我可以假设金额将远低于10亿,因此32位INT将起作用.

对于您的应用程序域,您可能可以对进行类似的估计,其中可能是可能的.然后,您可以在这些点上添加检查或选择其他数据类型(如果有).

其他推荐答案

int a, b;
b = abs(a); // will overflow if a = 0x80000000
if (b < 0) printf("overflow");  // optimized away 

(您似乎在假设2s补充...让我们来运行)

谁说abs(a)"溢出"如果a具有该二进制模式(如果a是INT_MIN,则更准确地说)? abs(int)的Linux Man页面说:

尝试采用最负整数的绝对值未定义.

未定义并不一定意味着溢出.

因此,您的前提是b可能少于0,这是对"溢出"的测试,从一开始就从根本上存在缺陷.如果要测试,则无法对可能具有不确定行为的结果进行操作 - 而在操作之前进行!

如果您关心此,则可以使用C ++的用户定义类型(即类)来实现自己所需的操作(或找到已经执行此操作的库)的测试集.该语言不需要对此的内置支持,因为它可以在这样的库中同样有效地实现,并且所得的使用语义不变.这是基本力量是关于C ++的伟大事物之一.

其他推荐答案

问问自己:您实际上需要一次检查一次算术?如果您经常需要它,则应编写一个checked_int类,该类超载通用操作员并将支票封装到此类中.在开源网站上共享实施的道具.

更好(可以说),使用big_integer类,以便首先不会发生溢出.

本文地址:https://www.itbaoku.cn/post/359198.html