You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

诊所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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:20:32