我观察到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/