C 语言缓冲区溢出与安全
更新时间:2026-08-26。本文是
languages/c/主题高手层的骨架文档(占位),完整展开将在后续批次补齐。
本文要回答的问题
- 缓冲区溢出是怎么发生的?它为什么能"改写程序"?
- 哪些函数是重灾区?安全的替代是什么?
- 栈保护、ASLR 这些机制在防什么?
一、原理
写入的字节数超过了分配的空间,覆盖了相邻内存。栈上的局部数组越界写,会一路覆盖返回地址——函数返回时跳到攻击者控制的位置,程序行为就被劫持了。
c
char buf[16];
strcpy(buf, "很长很长的字符串……"); /* 溢出了 */二、危险函数与替代
| 危险函数 | 问题 | 安全替代 |
|---|---|---|
gets | 完全不限长度 | fgets(buf, size, stdin) |
strcpy | 不检查目标容量 | strncpy/snprintf/strlcpy |
sprintf | 不检查目标容量 | snprintf(buf, size, ...) |
strcat | 不检查总容量 | strncat 或先算长度 |
scanf("%s") | 无限读入 | 用 %Ns 限制或 fgets |
通用原则:给缓冲区操作用"带长度的版本",且长度传的是缓冲区真实容量。
三、现代缓解机制
| 机制 | 作用 |
|---|---|
| 栈保护(canary) | 返回地址前放随机哨兵值,被覆盖则崩溃告警(-fstack-protector) |
| ASLR | 栈/堆/库地址随机化,让固定地址攻击失效 |
| PIE | 可执行文件本身随机加载 |
| NX | 栈数据不可执行 |
这些机制让"溢出"从"轻易得手"变成"多半崩溃"——但正确写法才是根本。
四、检测与排查
- ASan:
-fsanitize=address运行时抓越界读写(含堆/栈),见 ASan 内存检测。 - Valgrind:内存错误检测,见 Valgrind 内存检测。
- 栈溢出崩溃的 gdb 分析,见 段错误与 core dump。
五、与入门层的衔接
一句话总结
缓冲区溢出是"写超了空间、劫持了流程":拒绝 gets/strcpy/sprintf 三兄弟、一律用带容量的函数,再配栈保护与 ASan 兜底——安全从源头写法开始。
本文为骨架文档:核心结构已就位,示例代码与实测数据将在后续批次补齐。