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

Hen*_*iam 5 c++ 64-bit portability 32bit-64bit

我在准备用于 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
}
Run Code Online (Sandbox Code Playgroud)

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

静态分析工具很有用,但它们不能直接检测这种错误。(无论如何还没有。)计数器n根本不参与while表达式,所以这不像其他循环那样简单(类型转换错误会导致错误消失)。任何工具都需要确定循环将执行超过 2 31次,但这意味着它需要能够估计表达式(pos = find(ch, start)) != npos将评估为真的次数——这可不是一件小事!即使一个工具可以确定循环可以执行超过 2 31次(比如说,因为它识别出find函数正在处理一个字符串),它怎么知道循环不会执行超过 2 64 次次,也溢出一个size_t值?

似乎很明显,要最终识别和修复此类错误需要人眼,但是否有模式可以泄露此类错误,以便可以手动检查?我应该注意哪些类似的错误?

编辑 1:由于short,intlong类型本质上是有问题的,因此可以通过检查这些类型的每个实例来发现这种错误。但是,鉴于它们在遗留 C++ 代码中无处不在,我不确定这对于大型软件是否实用。还有什么给出了这个错误?每个while循环都可能会出现这样的错误吗?(for循环当然不能幸免!)如果我们不处理 16 位类型,那么这种错误有多严重short

编辑 2:这是另一个示例,显示此错误如何出现在for循环中。

int i = 0;
for (iter = c.begin(); iter != c.end(); iter++, i++)
{
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

从根本上来说,这是同一个问题:循环依赖于一些永远不会直接与更广泛的类型交互的变量。变量仍然可能溢出,但没有编译器或工具检测到转换错误。(严格来说,没有。)

编辑 3:我正在使用的代码非常大。(仅 C++ 就有 10-15 百万行代码。)检查所有这些代码是不可行的,所以我对自动识别此类问题的方法(即使它导致高误报率)特别感兴趣。

Ben*_*igt 1

代码审查。让一群聪明人查看代码。

使用shortint、 或long是一个警告信号,因为标准中没有定义这些类型的范围。大多数用法应更改为int_fastN_t中的新类型<stdint.h>,处理序列化的用法为intN_t. 好吧,实际上这些<stdint.h>类型应该用于typedef新的特定于应用程序的类型。

这个例子确实应该是:

typedef int_fast32_t linecount_appt;
linecount_appt n;
Run Code Online (Sandbox Code Playgroud)

这表达了行数适合 32 位的设计假设,并且如果设计要求发生变化,也可以轻松修复代码。

  • 如果有超过 1000 万行代码需要查看怎么办?查看每一个short、int和long是否可行?以不同的方式询问:对于 64 位可移植性,是否总有比使用 Short、int 或 long 更好的替代方案? (3认同)