2012-03-15 129 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];