C语言fopen打开不存在文件返回值异常触发段错误排查
C语言文件处理模块段错误与错误码失效问题排查
问题背景
程序预设逻辑为输入文件无法打开或不存在时返回错误码2,实际运行时触发段错误。测试用有效输入文件已放置在程序运行目录,设计逻辑为通过命令行参数传入文件名即可正常打开对应文件。
涉及的输入文件处理模块代码如下:
int max_plateau = 0; for (int i = 1; i < argc - 1 ; i++) { FILE *input = fopen(argv[i], "r"); if (ferror(input)) { return 2; } else { read_file(input, &bridges, &count, max_plateau); if (max_plateau != 0) { bridges[max_plateau - 1] += 1; bridges[max_plateau] += 1; } max_plateau = count; fclose(input); } }
输出文件处理模块代码如下:
if (argv[argc - 1] == NULL) return 2; else { int odd = 0; find_result(&ungerade, anzahl, &bruecken); FILE *output = fopen(argv[argc - 1], "w"); if (ferror(output)) { if (bridges != NULL) { free(bridges); } return 2; } else { print(output, odd, &bridges, count); fclose(output); } }
故障根因
- 段错误直接触发原因:
fopen()打开文件失败时会返回NULL空指针,代码未检查该返回值,直接将空指针传入ferror(),函数尝试访问空指针指向的非法内存地址,直接触发段错误,导致预设的返回错误码2的逻辑完全无法执行。 - 接口用法错误:
ferror()的作用是检查已成功打开的有效FILE流上是否发生读写错误,本身不能用来判断fopen()是否执行成功。判断文件打开成功与否的唯一标准是检查fopen()返回值是否为NULL。 - 参数校验逻辑无效:输出模块中
if (argv[argc - 1] == NULL)属于无效判断。C语言标准规定argv数组最后一个有效元素下标为argc-1,argv[argc]才固定为NULL,只要程序正常启动,argv[argc-1]不可能为NULL,这段校验完全起不到参数检查的作用。如果需要校验参数数量是否符合要求,应当提前判断argc是否达到最小要求(例如至少需要1个输入文件+1个输出文件时,需判断argc >= 3,不满足直接返回错误码)。 - 潜在越界风险:代码中存在
bridges[max_plateau - 1]、bridges[max_plateau]的数组访问操作,如果read_file()函数中为bridges分配的内存长度不足,或者count值超出数组实际边界,也会触发数组越界导致段错误。
修复方案
- 所有
fopen()调用后,第一时间检查返回值是否为NULL,如果是则直接走错误处理逻辑返回2,禁止对空指针执行任何文件操作。
输入模块的文件打开校验逻辑修改示例:FILE *input = fopen(argv[i], "r"); if (input == NULL) { // 直接判断fopen返回值,替代原有ferror判断 return 2; } - 输出模块的文件打开校验逻辑做相同修改,先判断
fopen()返回的output指针是否为NULL,再执行后续的写文件、资源释放操作。 - 删除无效的
argv[argc-1] == NULL判断,补充参数数量校验逻辑:程序启动后先判断argc是否满足最小参数要求,不满足直接返回错误码2。 - 排查
read_file()函数中bridges数组的内存分配逻辑,确保数组分配长度大于等于count的最大可能值,避免数组越界访问。
内容的提问来源于stack exchange,提问作者Bassel Sinokrot
相关产品推荐
相关产品推荐

