Strcat堆栈粉碎行为

时间:2014-05-09 00:33:34

标签: c gcc memory stack strcat

当运行以下故意堆栈粉碎代码时,strcat会将源的值复制十次。

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

int main() {
    char a[16];
    char b[16];
    char c[32];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

输出:

  

a = abcdefghijklmnop b = c =

     

a = abcdefghijklmnopABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOP c =

     

a = abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP b =   ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP c = ABCDEFGHIJKLMNOP

     

a =   abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP   b =   ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP   c =   ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

     

**堆栈粉碎检测到 * :./ sctrcpytest终止

构建参数:

  

gcc -O0 -g3 -Wall -c -fmessage-length = 0

代码在x86_64架构上运行。

为什么它只连接十次?

3 个答案:

答案 0 :(得分:2)

对于重叠字符串,未定义strcpy()和strcat()的行为。因此,您对c []的两次写入都是可疑的,而不仅仅是测试粉碎堆栈,您还在测试编译器对此未定义行为的处理。

我希望strcpy(c,b)行失败,但是实现必须以某种方式得到b的长度才能在c的开头覆盖尾随的零。例如,如果它从最后一个字节复制到第一个字节,就会发生这种情况。

strcat(c,b)可以以更直接的方式实现。也许十倍的数据足以达到终止它的一些限制。

如果您想测试破坏堆栈,请不要使用这些方法。而是只使用一个数组,并用循环写过它的末尾,例如“for(i = 0; i&lt; 1000000; i ++)c [i] ='h';”

答案 1 :(得分:0)

如果您的平台使用内存保护并且其堆栈逐渐增长,例如x86(What is the direction of stack growth in most modern systems?),那么选择任何堆栈位置并从那里写入增加的地址(例如字符串...)意味着您不要不要去堆栈扩展的方向但是堆栈的起源,最终会在它上面运行并在一个非映射的保护页面上陷入死亡,在这种情况下你会得到你提到的错误信息。

错误消息可以并且以这种方式进行个性化,以便提示您发生了什么。

除此之外:更改任何内容可能会改变代码的行为,因为平台没有义务以这种方式行事。
抛开第二个:令人震惊的是,strcpy(c, b);的行为就好像它没有覆盖从b开始并在c中终止的字符串的终结符。

答案 2 :(得分:-1)

我使用gcc编译器得到这样的输出:

a = abcdefghijklmnop
b = 
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOP

a = 
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

这是因为您没有为终结器提供所需的大小。试试吧:

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

int main() {
    char a[17];
    char b[17];
    char c[33];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

现在一切都很好。 谢谢Baldrick。