dest缓冲区小于src缓冲区时的strcpy

时间:2009-10-21 15:53:43

标签: c string buffer-overflow strcpy

我试图了解strcpy和strncpy的区别/缺点。 有人可以帮忙:

void main()
{
char src[] = "this is a long string";
char dest[5];

strcpy(dest,src) ;
printf("%s \n", dest);
printf("%s \n", src);

}

输出结果为:

this is a long string 
a long string 

问题:我不明白,源sting是如何被修改的。根据解释,strcpy应该继续复制,直到它遇到'\ 0',所以它确实如此,但为什么“src”字符串被修改。

请解释一下。

7 个答案:

答案 0 :(得分:11)

简单的答案是你(使用strcpy()调用)做了一些超出系统规范的东西,因此当之无愧地受到了不确定的行为。

更难的答案是检查系统上的具体内存布局,以及strcpy()如何在内部工作。它可能是这样的:

     N+28 "g0PP"
     N+24 "trin"
     N+20 "ng s"
     N+16 "a lo"
     N+12 " is "
src  N+08 "this"
     N+04 "DPPP"
dest N+00 "DDDD"

字母D代表dest中的字节,字母P是填充字节,0字符是用作字符串终止符的ASCII NUL字符。

现在strcpy(dest,src)会稍微改变内存内容(假设它正确处理重叠的内存区域):

     N+28 "g0PP"
     N+24 "trin"
     N+20 "g0 s"
     N+16 "trin"
     N+12 "ng s"
src  N+08 "a lo"
     N+04 " is "
dest N+00 "this"

即。而dest现在“包含”完整字符串“这是一个长字符串”(如果计算溢出的内存),src现在包含一个完全不同的NUL终止字符串“一个长字符串”。

答案 1 :(得分:7)

这是缓冲区溢出和未定义的行为。

在您的情况下,似乎编译器已将destsrc按顺序放入内存中。当您从src复制到dest时,会继续复制dest的结尾并覆盖src的一部分。

答案 2 :(得分:1)

具有高度的喜好,字符串是确切的邻居。所以在你的情况下你可能有这张照片

dst | | | | | src | | | | | |

所以你开始写,发生src的字段被覆盖。

但是,你肯定不会依赖它。一切都可能发生,你所拥有的是未定义的行为。因此,在另一台计算机上可能会发生其他事情和/或其他选择。

此致 弗里德里希

答案 3 :(得分:1)

您的代码导致缓冲区溢出 - 复制到比其可容纳的更多字符。 附加的字符写在堆栈的另一个地方,在你的情况下,src指向的地方。

您需要使用strncpy()功能。

答案 4 :(得分:1)

作为补充说明,请记住,当您需要使用缓冲区溢出保护执行复制时,strncpy功能不是正确的功能。此功能并非用于此目的,并且从未用于此目的。 strncpy是一个很久以前创建的函数,用于在某些旧版UNIX中的某些非常特定的文件系统中执行某些特定于应用程序的字符串复制。不幸的是,图书馆的作者设法“劫持”通用名称strncpy以用于非常狭隘和特定的目的。然后将其保留以用于向后兼容目的。而现在,我们有一代或两代程序员只根据其名称对strncpy的目的作出假设,因此使用它不正确。实际上,strncpy几乎没有任何有意义的用途。

C标准库(至少其C89 / 90版本)不提供具有缓冲区溢出保护的字符串复制功能。为了执行此类受保护的复制,您必须使用某些特定于平台的功能,例如strlcpystrcpy_s或自己编写一个。

P.S。 StackOverflow上的这个thread包含了关于为strncpy开发的真实目的的一个很好的讨论。请参阅此post以获取有关其在UNIX文件系统中的角色的精确说明。另外,请参阅here,了解有关strncpy如何成为的好文章。

再次,strncpy是一个复制完全不同类型的字符串 - 固定长度字符串的函数。它甚至不打算与传统的C风格的空终止字符串一起使用。

答案 5 :(得分:0)

我建议您快速阅读:

http://en.wikipedia.org/wiki/Strncpy#strncpy

显示了差异。基本上strncpy允许您指定要复制的字节数,这意味着结果字符串不一定是无效的。

现在当你使用strcpy将一个字符串复制到另一个字符串时,它不会检查结果的内存区域以查看它是否足够大 - 它在这方面没有牵着你的手。它会检查src字符串中的空字符。

当然,这个例子中的dst只有5个字节。那会发生什么?它一直在写作,到达目的地的末尾,并在记忆中超越它。在这种情况下,堆栈上的下一部分内存是你的src字符串。因此,虽然你的代码不是故意复制它,但是内存中的字节布局加上dst结束后的写入导致了这一点。

希望有所帮助!

答案 6 :(得分:0)

要么我误解了你的问题,要么你误解了strcpy:

  

问题:我不明白,怎么样   源sting得到修改。按照   解释,strcpy应该保留   复制,直到它遇到'\ 0',所以   它确实如此,但为什么“src”字符串得到了   修改。

听起来像是在期待strcpy在到达dest结束时停止复制到dest,基于看到\0字符。这不是它的作用。 strcpy复制到目标,直到它到达源字符串的末尾,由\0字符分隔。它假定您为副本分配了足够的内存。在复制之前,dest缓冲区可以包含所有空值。

strncpy通过让你实际告诉它你要复制的缓冲区有多大来解决这个问题,这样你就可以避免它复制的数量超过适合的情况。