一句话理解 gets
「gets 就像一个不设防的‘输入黑洞’,贪婪吞噬用户输入直到换行,但极易引发缓冲区溢出灾难!」
( 注意:gets 已从C11标准中移除,绝对禁止在实际开发中使用!以下内容仅供学习历史代码参考。)
函数原型
#include
char *gets(char *str); // 危险!已被废弃!
入口参数
参数 | 类型 | 比喻解释 |
str | char* | 存放输入的「脆玻璃瓶」(字符数组) |
返回参数
返回值 | 含义 |
char* | 成功时返回 str 指针 |
NULL | 输入失败或遇到EOF |
灾难代码示例
场景1:缓冲区溢出导致程序崩溃
#include
int main() {
char fragile_bottle[5]; // 只能装4字符+1个\0
printf("输入你的名字:");
gets(fragile_bottle); // 危险操作!
printf("你好,%s!\n", fragile_bottle);
return 0;
}
输入测试:
输入:Alexander
输出:你好,Alexander!
(实际已溢出,可能触发段错误/修改其他内存)
场景2:安全漏洞演示(密码绕过)
#include
#include
int check_password() {
char password[8] = "secret";
char input[8];
printf("输入密码:");
gets(input); // 输入超长可覆盖password数组
return strcmp(input, password) == 0;
}
int main() {
if (check_password()) {
printf(" 登录成功");
} else {
printf(" 密码错误");
}
return 0;
}
攻击测试:
输入:aaaaaaaaaaaaaaa
(溢出input数组,覆盖password为aaa...)
输出: 登录成功
安全替代方案:fgets
#include
#include
void safe_input(char *buf, int size) {
fgets(buf, size, stdin); // 安全读取
buf[strcspn(buf, "\n")] = '\0'; // 去除换行符
}
int main() {
char safe_bottle[5];
printf("输入你的名字:");
safe_input(safe_bottle, sizeof(safe_bottle));
printf("你好,%s!\n", safe_bottle);
return 0;
}
输入测试:
输入:Alexander
实际存储:"Alex"(自动截断,避免溢出)
技术解剖
特性 | gets | fgets |
缓冲区检查 | 无 | 明确指定最大长度 |
换行符处理 | 丢弃 | 保留并存入缓冲区 |
安全性 | 极易引发溢出攻击 | 安全可靠 |
历史教训
- 1988年莫里斯蠕虫病毒:利用 gets 的溢出漏洞感染了全球10%的互联网计算机。
- CWE-242:被列为「危险函数黑名单」头号危险函数。
- 现代编译器态度:
# GCC编译警告
warning: the `gets' function is dangerous and should not be used.
总结
- 像定时炸弹:gets 是C语言历史上最臭名昭著的函数之一。
- 必须遵守:
1 永远不要使用 gets
2 用 fgets 或 getline 替代
3 开启编译器安全选项(如 -Wall -Werror)