內存問題是 C/C++ 開發中最隱蔽、最致命的 Bug 來源。本文總結實戰中遇到的棧溢出、堆洩漏、緩衝區越界、危險函數替換等典型場景,提供系統化診斷思路與工具鏈。
void fn(void) {
char a[100];
char *p = a;
bzero(p, 1000); // 寫入 1000 字節 → 棧溢出
}
*** stack smashing detected *** 並中止ret 指向隨機地址 → Segmentation fault 或異常執行流(gdb) r
*** stack smashing detected ***
Program received signal SIGABRT, Aborted.
0x0012d422 in __kernel_vsyscall ()
(gdb) bt
#0 0x0012d422 in __kernel_vsyscall ()
#1 0x001714d1 in raise ()
#2 0x00174932 in abort ()
#3 0x001a7fc5 in __fortify_fail ()
#4 0x00228008 in __stack_chk_fail ()
#5 0x080484b2 in fn () at test.c:8 ← 關鍵行:fn() 第 8 行
#6 0x00000000 in ?? ()
技巧:啟用編譯器棧保護 -fstack-protector-strong (GCC/Clang 默認開啟),配合 GDB bt 秒級定位。
若無明顯崩潰,可用 watch 監視可疑變量:
(gdb) watch suspicious_var
(gdb) c
Hardware watchpoint 2: suspicious_var
Old value = 42
New value = 0xdeadbeef
0x080485xx in some_function () at buggy.c:123 ← 修改該變量的具體指令
唯一原因:malloc/new 後缺少對應 free/delete。
valgrind --leak-check=full --show-leak-kinds=all ./your_program
輸出包含:
配合 --track-origins=yes 可追溯未初始化值來源。
char buf[100000] 直接導致棧溢出 (默認棧 8MB)。大緩衝區必須用堆 (malloc/new/std::vector) 或靜態存儲 (static/global)realloc、C++ 用 std::string/vector 自動管理以為 snprintf 安全 → strncpy 也安全?錯!
char a[10];
snprintf(a, sizeof(a), "hello"); // 安全:截斷並保證 \0 結尾
strncpy(a, "hello", 100); // 崩潰!寫入 100 字節 (補 \0 到 100)
strncpy(a, "hello", sizeof(a)); // 危險:若源長度 ≥ 10,目標缺 \0 結尾
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null terminated.
If the length of src is less than n, strncpy() pads the remainder of dest with null bytes.
| 危險函數 | 安全替代 | 關鍵差異 |
|---|---|---|
sprintf | snprintf | 長度限制 + 保證 \0 |
strcpy | strncpy (謹慎) / strlcpy (BSD) / std::string | strncpy 不保證 \0 結尾,需手動 dest[n-1]=0 |
strcat | strncat / strlcat / std::string | 同理 |
gets | fgets / std::getline | gets 無長度檢查,C11 已移除 |
scanf("%s") | scanf("%99s", buf) / fgets | 限制寬度 |
-Wall -Wextra -Werror -fstack-protector-strong -D_FORTIFY_SOURCE=2 (Release 也要開)-fsanitize=address), MemorySanitizer, Valgrind — 測試環境常駐std::unique_ptr/shared_ptr, std::string/vector/span;禁止 alloca/VLAulimit -c unlimited + gdb ./exe core + bt — 生產環境最後防線「程序出問題不可怕,可怕的是拒絕面對詭異現象。每一個『見鬼』的 Bug,最終都指向某行違背內存規範的代碼。冷靜、工具、證據鏈 —— 你一定能找到它。」