c – 如何检测难以捉摸的64位可移植性问题?

我在一些(C)代码中找到了与此类似的代码片段,我正准备使用64位端口.

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
}

虽然我严重怀疑这实际上会导致内存密集型应用程序出现问题,但从理论角度来看值得考虑,因为类似的错误可能会导致问题. (在上面的示例中将n更改为short,即使是小文件也可能会溢出计数器.)

静态分析工具很有用,但它们无法直接检测到这种错误. (还没有,无论如何.)计数器n根本不参与while表达式,所以这并不像其他循环那样简单(类型转换错误会导致错误).任何工具都需要确定循环执行次数超过231次,但这意味着它需要能够估计表达式(pos = find(ch,start))!= npos将被评估为真的次数 – 否小壮举!即使一个工具可以确定循环可以执行超过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代码的代码为1000万到1千万行.)检查所有代码是不可行的,所以我特别感兴趣的方法是自动识别这类问题(即使它会导致很高的误报率).

最佳答案 代码评论.让一群聪明的人看着代码.

使用short,int或long是一个警告标志,因为标准中未定义这些类型的范围.大多数用法应更改为< stdint.h>中的新int_fastN_t类型,用于处理序列化为intN_t的用法.好吧,实际上这些< stdint.h>类型应该用于键入新的特定于应用程序的类型.

这个例子应该是:

typedef int_fast32_t linecount_appt;
linecount_appt n;

这表示一种设计假设,即线计数适合32位,并且如果设计要求发生变化,也可以很容易地修复代码.

点赞