Fortify表示这是一个越界读取:
if (strncmp("test string", "less than 32 char", 32) == 0)
{
...
}
它指出该函数从小于32个字符
的范围外读取数据。
如果strncmp
超出32个字符并且第二个字符串少于32个字符,是否确实存在此问题?
出于性能方面的考虑,标准字符串函数的实现通常会以自然对齐寄存器宽度块的形式处理数据。这可能会导致读取超出源数据对象末尾的访问,但是对齐保证了代码在内存异常方面的行为与天真实现完全相同。每个宽度访问都包含在单个页面中,并且不会触及任何不会被字节方式实现所触及的页面。
我认为这样的实现受到C语言的"as-if"规则的覆盖,也就是说,它们的行为与抽象的功能规范一样。
这样优化的实现示例可以参考OpenSolaris的SPARC v8架构下的strcmp()
。这是我十五年前编写的代码,还有其他性能优化的字符串函数。
然而,各种内存检查工具会抱怨此类代码,因为使用它可能会导致超出分配的数据对象的限制,即使由于设计原因,越界读取访问是无害的。
TL;DR - strncmp()
将继续比较字符串的元素,直到任一字符串的结尾或32个元素(字符),以较少的那个为准。
任何字符串都是以空字符结尾的,在遇到空字符终止符后,不会进行进一步的比较。您的代码是安全的。
引用C11, 章节§7.24.4.4 (我强调的)
int strncmp(const char *s1, const char *s2, size_t n);
strncmp
函数比较从指向s1
的数组开始到指向s2
的数组的不超过n
个字符(不会比较空字符后面的字符)。
您的代码完全有效。
要么是编译器生成了错误的目标代码,要么是Fortify报告了一个误报。
我怀疑编译器会生成错误的代码。这将会带来太多问题,并且很快就会被发现和修复。
很可能是Fortify误报了。
strncmp()
实现来说是这样的。 - alkstrncmp()
只需要比较你的示例字符串中每个字符串的一个char
。我赞同这是误报。 - EOF