考虑:
constexpr char s1[] = "a";
constexpr char s2[] = "abc";
std::memcmp(s1, s2, 3);
如果memcmp
在它看到的第一个差异处停止,它将不会读取超过s1的第二个字节(nul终结符),但是我没有看到C标准中的任何内容来确认此行为,并且我不知道C ++中的任何扩展它的东西。
n1570 7.24.4.1 PDF link
int memcmp(const void *s1, const void *s2, size_t n);
memcmp
函数将n
指向的对象的第一个s1
字符与s2
指向的对象的前n个字符进行比较
我的理解是否正确,标准将行为描述为读取两个参数的所有n
个字节,但是库可能会短路 - 如果它们发生了?
答案 0 :(得分:5)
该功能无法保证短路,因为标准并未说明必须。
不仅不能保证短路,而且在实践中许多实现都不会。例如,glibc比较类型unsigned long int
的元素(最后几个字节除外),因此它可以读取超过该位置的7个字节,在64位实现上进行不同的比较。
有些人可能认为这不会导致平台glibc目标上的访问冲突,因为对这些unsigned long int
的访问将始终对齐,因此不会跨越页面边界。但是当两个源具有不同的对齐时,glibc将从其中一个源读取两个连续的unsigned long int
s,这些源可能位于不同的页面中。如果不同的字节位于第一个字节中,则在glibc执行比较之前仍然可以触发访问冲突(参见函数memcmp_not_common_alignment
)。
简而言之:即使在此长度之前出现不同的字节,指定小于缓冲区实际大小的长度也是未定义的行为,并且可能导致常见实现崩溃。
以下是可以崩溃的证据:https://ideone.com/8jTREr