检测到堆栈粉碎。有人可以解释原因吗?

时间:2017-09-18 14:59:19

标签: c string pointers

这是我的gcc版本:

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

我有一个简单的C程序,它将源字符串连接到目标。

#include<stdio.h>

void Strcat(char *t, char *s){  
    while(*t++);
    t--;
    while(*t++=*s++);
}

void main(void){
    char target[8] = "stack";
    char *source = "overflow";
    printf("%s\n", target);
    Strcat(target,source);
    printf("%s\n", target);
}

上面的程序给出了这个输出错误:

$ a.out 
stack
stackoverflow
*** stack smashing detected ***: a.out terminated
Aborted (core dumped)

但是当我初始化大小为9而不是8的目标数组时,如下所示,该程序产生正确的输出。

#include<stdio.h>

void Strcat(char *t, char *s){  
    while(*t++);
    t--;
    while(*t++=*s++);
}

void main(void){
    char target[9] = "stack";
    char *source = "overflow";
    printf("%s\n", target);
    Strcat(target,source);
    printf("%s\n", target);
}

有人可以解释为什么第一个变体会产生堆栈粉碎错误吗?

3 个答案:

答案 0 :(得分:4)

两者的情况下,您的目标太小而无法保存连锁结果。因此,在Strcat()函数内部,您将访问超出范围的内存,从而导致undefined behavior

一旦你点击UB,就没有解释原因,因为,没有明确的方法来解释结果。

因此,在传递目标以存储连接结果之前,需要确保目标有足够的内存来存储连接结果,以及空终止符。

答案 1 :(得分:2)

这两个程序都有未定义的行为,因为数组target之外的内存被覆盖,错误消息说明了这一点。

第二个程序给出预期结果的原因可以通过以下方式解释。

将类型为source的变量char *放置在内存中,以便在变量target之后正确对齐指针。因此,变量taget被声明为

char target[9] = "stack";
           ^^^

编译器可以在内存中附加额外的字节,以便为以下变量提供所需的对齐

char *source = "overflow";

这些额外的字节可以由函数Strcat使用。

答案 2 :(得分:0)

两个程序都是UB,但在第二种情况下,堆栈防护在下一个堆栈对齐后放置。通常是8个字节。所以你没有覆盖警卫而你没有得到错误。

但你仍然在界外写作。