Microsoft的strncat读取源缓冲区边界之外的字节

gla*_*lig 6 c pageheap

我观察到Microsoft实现的一个有趣的问题strncat.它接触源缓冲区之外的1个字节.请考虑以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

void main()
{
    char dstBuf[1024];
    char* src = malloc(112);
    memset(src, 'a', 112);
    dstBuf[0] = 0;
    strncat(dstBuf, src, 112);
}
Run Code Online (Sandbox Code Playgroud)

strncat112字节块后读取1个字节.因此,如果您不幸在无效页面边界上进行分配,则应用程序崩溃.大型应用程序可能会在这些地方间歇性地崩溃.(请注意,可以使用gflags PageHeap设置模拟此类条件;块大小必须能够被指针大小整除才能正确对齐.)

这是预期的行为还是错误?任何确认的链接?(我阅读了几个描述,strncat但它们可以通过两种方式解释,具体取决于你最初的想法......)

更新(回答有关证据的问题):如果从上面的文字中不清楚,我道歉,但这是一个实验性的事实.我在strncat读取地址src + srcBufSize 的应用程序中观察到间歇性崩溃.在这个小例子中,gflags PageHeap在崩溃时运行一致(100%).所以据我所知,证据非常可靠.

Update2(编译器信息)MS Visual Studio 2005版本8.0.50727.867.构建平台:64位版本(32位无repro).用于重现崩溃的操作系统:Windows Server 2008 R2.

更新3此问题还使用MS Visual Studio 2012 11.0.50727.1中内置的二进制文件重现

更新4 链接以在Microsoft Connect上发布 ; 链接到MSDN论坛上的讨论

更新5问题将在下一个VS版本中修复.旧版本没有计划修复.请参阅上面的"Microsoft Connect"链接.

Gre*_*ill 3

状态的strncat文档:

src - 指向要复制的以空结尾的字节字符串的指针

因此,实现可以假设src输入参数实际上以 NUL 结尾,即使它比count字符长。

为了进一步确认,微软自己的文档指出:

字符串源

以 Null 结尾的源字符串。

另一方面,实际的 C 标准规定如下:

strncat函数从 指向的数组向 指向的字符串末尾追加不超过几个n字符(不追加空字符和其后s2的字符) s1

正如下面的注释中所指出的,这将第二个参数标识s2数组而不是以 NUL 结尾的字符串。然而,这相对于最初的问题仍然不明确,因为本文档描述了对 的最终影响s1,而不是从 读取时函数的行为s2

当然,这可以通过查阅 C 运行时库源代码来解决具体的Microsoft 实现。

  • @GregHewgill:这与将源操作数视为数组的 C 标准冲突:_strncat() 函数应从 s2 指向的数组附加不超过 n 个字节(不附加空字节和后面的字节)到 s1._ 指向的字符串末尾 (4认同)
  • @glagolig:你的链接说“C string”。C 字符串始终以 NUL 结尾。 (3认同)
  • @JonathonReinhart:这就是结果*行为*,但输入的`src`字符串仍然预计以空结尾。 (2认同)