2012-03-15 127 views
4

我创建了一个文件,打印你好,世界多次在用户想要输入。c堆栈粉碎检测

#include <stdio.h> 
#include <string.h> 
int main() { 
    char message[10]; 
    int count, i; 

    strcpy(message, "Hello, world!"); 

    printf("Repeat how many times? "); 
    scanf("%d", &count); 

    for(i=0; i < count; i++) 
     printf("%3d - %s\n", i, message); 
} 

无论输入什么数字,它总是会导致“堆栈粉碎”。这是该计划,任何人都可以得出结论,为什么它这样做?这里是“回溯”之后检测堆栈粉碎发生:

[email protected]:~/programming$ ./a.out 
Repeat how many times? 12 
    0 - Hello, world! 
    1 - Hello, world! 
    2 - Hello, world! 
    3 - Hello, world! 
    4 - Hello, world! 
    5 - Hello, world! 
    6 - Hello, world! 
    7 - Hello, world! 
    8 - Hello, world! 
    9 - Hello, world! 
10 - Hello, world! 
11 - Hello, world! 
*** stack smashing detected ***: ./a.out terminated 
======= Backtrace: ========= 
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0x1f8c75] 
/lib/i386-linux-gnu/libc.so.6(+0xe8c27)[0x1f8c27] 
./a.out[0x8048524] 
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x129113] 
./a.out[0x80483f1] 
======= Memory map: ======== 
00110000-00288000 r-xp 00000000 08:01 1577912 /lib/i386-linux-gnu/libc-2.13.so 
00288000-0028a000 r--p 00178000 08:01 1577912 /lib/i386-linux-gnu/libc-2.13.so 
0028a000-0028b000 rw-p 0017a000 08:01 1577912 /lib/i386-linux-gnu/libc-2.13.so 
0028b000-0028e000 rw-p 00000000 00:00 0 
0036b000-0036c000 r-xp 00000000 00:00 0   [vdso] 
00454000-00470000 r-xp 00000000 08:01 1573818 /lib/i386-linux-gnu/libgcc_s.so.1 
00470000-00471000 r--p 0001b000 08:01 1573818 /lib/i386-linux-gnu/libgcc_s.so.1 
00471000-00472000 rw-p 0001c000 08:01 1573818 /lib/i386-linux-gnu/libgcc_s.so.1 
00e7e000-00e9c000 r-xp 00000000 08:01 1573924 /lib/i386-linux-gnu/ld-2.13.so 
00e9c000-00e9d000 r--p 0001d000 08:01 1573924 /lib/i386-linux-gnu/ld-2.13.so 
00e9d000-00e9e000 rw-p 0001e000 08:01 1573924 /lib/i386-linux-gnu/ld-2.13.so 
08048000-08049000 r-xp 00000000 00:14 3801591 /home/sean/programming/a.out 
08049000-0804a000 r--p 00000000 00:14 3801591 /home/sean/programming/a.out 
0804a000-0804b000 rw-p 00001000 00:14 3801591 /home/sean/programming/a.out 
08a9e000-08abf000 rw-p 00000000 00:00 0   [heap] 
b77e8000-b77e9000 rw-p 00000000 00:00 0 
b77fc000-b7800000 rw-p 00000000 00:00 0 
bff87000-bffa8000 rw-p 00000000 00:00 0   [stack] 
Aborted 
+4

您可能会发现它有助于打开了你使用任何编译器警告。例如,当我在-Wall中使用gcc时,它产生了“警告:控制达到非void函数的结束”和“调用__builtin___strcpy_chk将总是溢出目标缓冲区”,后者明确指出问题所在。 – DSM 2012-03-15 00:44:03

回答

34

因为"Hello, world!"超过10个字符...

+10

instant classic – Ulterior 2012-03-15 01:27:30

2

message阵列必须至少有一个字符长度超过字符串你复制到它(记住你也需要保持隐含的'\0'空终止符)。

11

message只能容纳10个字节。您正在复制字符串“Hello World!”这是13字节(如果您计算空字符),您将最终覆盖并破坏堆栈保护cookie。

该cookie是由编译器插入的随机字节,以确保在堆栈上修改返回地址时防止崩溃,从而防止潜在的缓冲区溢出漏洞。

如果您正在使用gcc进行编译,那么尝试将-fno-stack-protector切换到您的编译语句并重试。该程序可能会崩溃(但不会出现类似的错误消息),并且容易受到缓冲区溢出攻击。

+0

注意:OP使用“Hello,World!” - 带0终止符的14个字节。 – mattnz 2012-03-15 01:50:42

+0

@mattnz哦,我错过了逗号。算了。没关系。我不会再编辑这个帖子:) – 2012-03-15 02:03:23

0

如前所述,Hello World!太长。更容易做到以下几点

char message[]="Hello World!"; 

这将是正确的大小自动。

+4

你可能要仔细检查一下...... – 2012-03-15 00:39:06

+0

糟糕...这就是我在同一时间使用过多的编程语言得到的... – PearsonArtPhoto 2012-03-15 01:45:40

3

您的消息数组长度为10个字符(0-9),但是如果您计数为"Hello, World!"(不带引号)则长度为13个字符。因此,您正在覆盖不属于阵列的内存。

作为参考,strcpy(), strcat()和大多数其他C字符串函数不检查数组的长度,他们认为你已经给它足够的空间来处理。

所以,你需要给你的消息数组更多的空间。但还有多少?足以适应“你好,世界!”再加上一个空终止符'\0',它决定了字符串的结尾。所以你需要声明一个14个字符的数组。

关于使用字符串和空字符的更深入的解释,我建议this page。虽然这是一个C++页它涵盖的东西,是C和C共同++(如C++是基于C)

而且,Pearsonartphoto说,你可以宣布你的数组作为

char message[] = "Hello, World!"; 

然而,如果这是为了学校或单独作业,请确保你已经被教导这样做,因为有时候你可以被扣除“冲向前”的标记。这些问题的想法是教导遗嘱,以及如何和为什么某些事情有效,它们可能不是最简单或最有效的做事方式(你所得到的堆栈式粉碎仍然会造成问题今天的主要系统,因为程序员忘记检查大小等)。

-1

我有这个问题时,我定义的这样一个结构:

struct data { 
...variables... 
char text[]; 
}; 

这不会给任何警告,但在我的案件引起了栈溢出错误。 我解决了代与

char text[100];