诊所C语言系统编辑患者信息触发stack smashing问题排查修复
栈溢出(Stack Smashing)问题排查与修复方案
问题成因
- 缓冲区越界写入:这是触发
stack smashing detected的核心原因。编辑患者信息时,若使用gets()、scanf("%s")这类不限制输入长度的函数,当输入的姓名、性别字符串长度超过预定义的数组缓冲区大小,会直接覆盖栈上的其他关键数据(如栈帧返回地址、栈保护校验位),触发GCC默认启用的栈保护机制,导致程序强制终止。 - 数组下标越界:修改患者信息时,若使用了超出患者数组合法范围的索引,会破坏栈内存结构,触发栈溢出检测。
- 输入格式不匹配:比如用字符串格式符读取年龄整数,或写入超出变量存储范围的年龄值,间接引发内存写入异常。
修复方案
1. 替换不安全输入函数
- 用
fgets()替代gets(),通过指定最大读取长度避免缓冲区溢出:// 示例:读取患者姓名,假设缓冲区大小为50 fgets(patient->name, sizeof(patient->name), stdin); // 移除fgets读取的换行符 size_t len = strlen(patient->name); if (len > 0 && patient->name[len-1] == '\n') { patient->name[len-1] = '\0'; } - 使用
scanf时限制输入长度,同时校验输入合法性:// 读取姓名:最多读取49个字符(预留1位给终止符'\0') scanf("%49s", patient->name); // 读取年龄:校验输入格式与范围 int age; if (scanf("%d", &age) != 1 || age < 0 || age > 120) { printf("年龄输入无效,请重新输入\n"); // 清理输入缓冲区残留字符 while(getchar() != '\n'); continue; } patient->age = age;
2. 严格校验数组索引
编辑患者前,先确认目标索引在合法范围内:
int index; printf("请输入要修改的患者索引:"); if (scanf("%d", &index) != 1 || index < 0 || index >= MAX_PATIENTS) { printf("无效的患者索引\n"); while(getchar() != '\n'); return; }
3. 规范结构体定义
确保患者信息结构体的成员大小足够覆盖实际输入需求:
typedef struct { char name[50]; // 预留足够空间存储姓名 char gender[10]; // 适配"男"/"女"/"未知"等性别标识 int age; } Patient;
4. 调试定位(可选)
用GDB调试定位具体越界位置:
gdb ./clinic_system run # 触发错误后,查看调用栈定位问题代码 bt
测试验证
修改后重点测试以下场景:
- 输入超过姓名缓冲区长度的字符串,确认程序无崩溃且提示输入过长
- 输入负数、超龄值等无效年龄,确认程序能正确处理并提示
- 输入超出患者数组范围的索引,确认程序能识别并报错
内容的提问来源于stack exchange,提问作者Ahmed A. Azmy
相关产品推荐
相关产品推荐

