如何发现难以捉摸的64位可移植性问题?

| 我正在为64位端口做准备的某些(C ++)代码中找到与此类似的代码段。
int n;
size_t pos, npos;

/* ... initialization ... */

while((pos = find(ch, start)) != npos)
{
    /* ... advance start position ... */

    n++; // this will overflow if the loop iterates too many times
}
尽管我严重怀疑这实际上甚至会在内存密集型应用程序中引起问题,但从理论的角度来看还是值得研究的,因为类似的错误可能会浮出水面,从而引起问题。 (在以上示例中,将“ 1”更改为“ 2”,即使是小文件也可能使计数器溢出。) 静态分析工具很有用,但它们无法直接检测到此类错误。 (无论如何,还没有。)计数器
n
根本不参与ѭ4so表达式,因此,它不像其他循环那么简单(在这里,类型转换错误使错误消失了)。任何工具都需要确定该循环将执行超过231次,但这意味着它需要能够估计表达式
(pos = find(ch, start)) != npos
将被评估为true的次数-不小的成就!即使工具可以确定该循环可以执行超过231次(例如,因为它识别出
find
函数正在处理字符串),它如何知道该循环执行的次数不会超过264次,因此溢出
size_t
值吗? 似乎很清楚,要最终确定并纠正这种错误需要肉眼观察,但是是否存在可以消除这种错误以便可以手动检查的模式?我应该注意哪些类似的错误? 编辑1:由于
short
int
long
类型本质上是有问题的,可以通过检查这些类型的每个实例来发现这种错误。但是,考虑到它们在传统C ++代码中无处不在,我不确定这是否适用于大型软件。还有什么可以解决这个错误?每个
while
循环是否都可能会出现这种错误? (
for
循环当然不能幸免!)如果我们不处理
short
这样的16位类型,这种错误有多严重? 编辑2:这是另一个示例,显示此错误如何在
for
循环中出现。
int i = 0;
for (iter = c.begin(); iter != c.end(); iter++, i++)
{
    /* ... */
}
从根本上说,这是同样的问题:循环指望永远不会直接与更大类型交互的变量。该变量仍然可以溢出,但是没有编译器或工具检测到强制转换错误。 (严格来说,没有。) 编辑3:我正在使用的代码很大。 (仅用于C ++的代码行为10-15百万行。)检查所有代码都是不可行的,因此我对识别此类问题的方式特别感兴趣(即使它会导致很高的假阳性率)费率)。     
已邀请:
        代码审查。让一群聪明的人看着代码。 使用
short
,ѭ9or或
long
是警告符号,因为标准中未定义这些类型的范围。大多数用法应在
<stdint.h>
中更改为新的
int_fastN_t
类型,并将处理序列化为
intN_t
。好吧,实际上这些
<stdint.h>
类型应该用于
typedef
种新的特定于应用程序的类型。 这个例子确实应该是:
typedef int_fast32_t linecount_appt;
linecount_appt n;
这表示了行数可以容纳32位的设计假设,并且如果设计要求发生变化,也可以轻松地固定代码。     
很明显,您需要一个智能的“范围”分析器工具来确定要计算的值范围与存储这些值的类型。 (您的基本反对意见是该智能范围分析仪是一个人)。您可能需要一些其他代码注释(通常放置在适当的typedef或断言中,以提供明确的范围约束)才能进行良好的分析,并处理其他任意大的用户输入。 您需要进行特殊检查才能处理C / C ++所说的算术合法但笨拙的地方(例如,假设您不希望[二进制补码]溢出)。 对于您的n ++示例(相当于n_after = n_before + 1),n_before可以是2 ^ 31-1(由于对字符串的观察),因此n_before + 1可以是2 ^ 32,这是溢出的。 (我认为标准的C / C ++语义表示可以毫无顾虑地溢出到-0)。 实际上,我们的DMS软件再造工具包内置了范围分析机制,但是目前尚未连接到DMS的C ++前端;我们只能这么快兜售:-{[我们已经在COBOL程序上使用它来解决涉及范围的各种问题]。 在没有这种范围分析的情况下,您可能会检测到具有这种相关流的循环的存在; n的值显然取决于循环计数。我怀疑这会给您带来副作用的程序中的每个循环,这可能并没有太大帮助。 另一位发布者建议使用特定于应用程序的类型(例如* linecount_appt *)以某种方式重新声明所有类似int的声明,然后对这些类型进行类型定义以评估对您的应用程序有效的值。为此,我认为您必须将每个类似int的声明归类(例如\\“这些声明都是* linecount_appt * \”)。通过手动检查10M SLOC来执行此操作似乎非常困难,而且容易出错。查找所有从“相同”值源接收(通过赋值)值的声明,可能是一种获取有关此类应用程序类型位置的提示的方法。您希望能够机械地找到这样的声明组,然后使用一些工具自动将实际的声明替换为指定的应用程序类型(例如* linecount_appt *)。这可能比进行精确范围分析要容易一些。     
        有一些工具可以帮助您发现此类问题。我不会在此处提供任何链接,因为我所知道的链接是商业性的,但应该很容易找到。     

要回复问题请先登录注册