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

时间:2013-08-30 03:36:58

标签: 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);
}

strncat在112字节块后读取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 Link to issue on Microsoft Connect; link to discussion on MSDN Forums

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

3 个答案:

答案 0 :(得分:3)

documentation for strncat州:

  

src - 指向要从

复制的以null结尾的字节字符串的指针

因此,实现可以假设src输入参数实际上是NUL终止的,即使它长于count个字符。

如需进一步确认,Microsoft's own documentation说明:

  

strSource

     
    

以空值终止的源字符串。

  

另一方面,actual C standard表示如下:

  

strncat函数附加的n字符不超过{null}字符   从s2指向的数组到结尾的跟随它的字符不会被附加   s1指向的字符串。

正如下面的评论中所指出的,这将第二个参数s2标识为数组,而不是以NUL结尾的字符串。但是,对于原始问题,这仍然是模棱两可的,因为此文档描述了对s1的最终影响,而不是从s2阅读时函数的行为。

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

答案 1 :(得分:2)

s2 <{1}}中的“字符串”。

因此,如果Microsoft正在读取strncat(s1, s2, n)个字节,那么它不符合C11。

C11 7.24.2.3.1 n提及
“将s2指向的字符串的副本(包括终止空字符)附加到s1”所指向的字符串的末尾。

C11 7.24.2.3.2 strcat()
“strncat函数从s2指向的数组到s1指向的字符串的末尾附加不超过n个字符(空字符及其后面的字符不会被追加)。 。终止空字符始终附加到结果“

显然,在strncat案例中,strncat被视为一个“数组”,对s2附加了多少字符串有限制。因此,在连接期间,不需要检查s1超过绝对需要的内容。最终写的s2来自代码,而不是\0

不了解较旧的C99标准。

答案 2 :(得分:1)

英语是一种不完美的语言,比C语言还要多。

文档说“在大多数 n个字符”(我的重点)。没有证据表明strncat复制超过112个字符。是什么让你相信它?

strncat的代码可能索引超过112的偏移量,但实际上不是参考偏移量113,这可能导致存储故障。该ptr行为在K&amp; R中被定义为可接受的。

最后,这又是一个英语/推理问题,文档可能会说空终止字符串。但实际上,说字符串是否为空终止不是多余的吗?它们是定义的,否则它们将是一个字符数组。因此,文档含糊不清且不具体。程序员可以在两行之间进行读取。软件文档不是合法的文档,它们是本领域技术人员理解的描述。