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,int和long类型本质上是有问题的,因此可以通过检查这些类型的每个实例来发现这种错误。但是,鉴于它们在遗留 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 百万行代码。)检查所有这些代码是不可行的,所以我对自动识别此类问题的方法(即使它导致高误报率)特别感兴趣。
代码审查。让一群聪明人查看代码。
使用short、int、 或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 位的设计假设,并且如果设计要求发生变化,也可以轻松修复代码。