我观察到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位无复制版)。
用来修复崩溃的操作系统: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”链接。

最佳答案

documentation for strncat 指出:



因此,该实现可以假定src输入参数实际上是NUL终止的,即使它比count字符长也是如此。

为了进一步确认,Microsoft's own documentation声明:



另一方面,actual C standard声明如下内容:



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

当然,这可以通过引用C运行时库源代码针对特定的Microsoft实现来解决。

关于c - 微软的strncat读取超出源缓冲区边界的字节,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18524508/

10-12 05:46