首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言陣列越界實戰案例:死迴圈成因分析與記憶體佈局圖解

     編輯:關於C語言

真實案例:密碼長度變更導致死迴圈

原始程式碼(正常)

#define USERCOUNT 20
char *passwordcommon = "passwd"; // 6 字元
char username[20];                // 20 位元組緩衝區
for (i=0; i

輸出正常,檔案內容:people0 passwd0\r\n ... people19 passwd19\r\n

修改後(死迴圈)

char *passwordcommon = "password"; // 8 字元,增加 2 字元

執行進入死迴圈,檔案寫入:

people0 password0
...
people10 password10
people11 password11  ← 卡在這裡無限重複
people11 password11
...

變數 i 永遠停留在 11(實際為 10,見下文分析)。

根因分析:緩衝區溢位覆蓋迴圈變數

記憶體佈局(32 位系統,棧向下增長)

高位址
+------------------+
| username[20]     |  ← 20 位元組緩衝區
+------------------+
| i (int, 4 bytes) |  ← 緊鄰 username 之後
+------------------+
| 其他區域變數...   |
低位址

溢位過程

  1. i=10 時,sprintf(username, "people%d password%d\r\n", 10, 10) 產生字串:
    "people10 password10\r\n" 長度 = 6+2+1+8+2+2 = **21 位元組**(含結束符 \0 共 22)。
  2. username 僅 20 位元組,**溢位 1~2 位元組**覆蓋緊鄰的 i 低位元組。
  3. i 原值 10 (0x0000000A),低位元組被 \n (0x0A) 或 \r (0x0D) 覆蓋,**數值恰好仍為 10 或變為 13**,導致迴圈條件 i < 20 永真,且 i++ 後又被下輪溢位覆蓋回原值。**形成死迴圈**。

經典教科書範例:同樣原理

int a[3] = {1,2,3};
int i;
for (i=1; i<=3; i++) {
    a[i] = 0; // i=3 時寫入 a[3],即 i 的位址
}
// 假設 i 位址 0x0022FF5C, a[3] 位址同樣 0x0022FF5C
// a[3]=0 導致 i=0,迴圈條件 i<=3 成立 → 死迴圈

防範對策

  1. 緩衝區預留足夠空間:char username[64]; 或動態計算所需長度。
  2. 使用安全函數:snprintf、strncat、strncpy 指定最大長度。
  3. 編譯器檢測:開啟 -fstack-protector-strong (GCC/Clang) / /GS (MSVC) 堆疊保護。
  4. 靜態分析:Cppcheck、Clang Static Analyzer、Coverity 掃描潛在越界。
  5. 現代 C++ 替代:std::string、std::vector、std::array 自動管理邊界。

核心教訓

C 語言不檢查陣列邊界,給予極大靈活性的同時,也將邊界檢查責任完全轉嫁給程式設計師。**緩衝區溢位不只是資安漏洞,更是導致邏輯錯誤(如死迴圈)的隱形殺手。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved