自定义get_next_line实现出现无效指针错误的排查求助
get_next_line 内存释放错误排查与修复
问题现象
实现的get_next_line函数存在以下异常:
- 读取文件最后一行时,
line变量持有该行内容,但在main函数循环内执行free(line)会触发无效指针错误; - 将
free移到循环外时读取正常,但会引发内存泄漏; - 仅当
BUFFER_SIZE设为1或10000时程序运行正常,设为10或100时出错,无法确定是main结构问题还是函数本身逻辑缺陷。
相关代码
main函数
int main(void) { int fd; char *line; fd = open("file.txt", O_RDONLY); while ((line = get_next_line(fd)) != NULL) { printf("%s", line); free(line); } printf("%s", line); free(line); return(0); }
get_next_line核心实现
#include "get_next_line.h" char *cut_line(char *line, char *new_line) { int i; i = 0; while (line[i] != '\n' && line[i] != '\0') i++; if (line[i] == '\n') i++; while (line[i]) { *new_line = line[i]; line[i] = '\0'; new_line++; i++; } while (*new_line) { *new_line = '\0'; new_line++; } return (line); } char *finalize_line(char **line, char **new_line) { *line = cut_line(*line, *new_line); if (**new_line == '\0') { free(*new_line); *new_line = NULL; } if (**line == '\0' && !*new_line) { free(*line); *line = NULL; return (NULL); } return (*line); } char *get_next_line(int fd) { static char *new_line; char *buffer; char *line; int read_bytes; buffer = ft_calloc(BUFFER_SIZE + 1, sizeof(char)); if (!new_line) new_line = ft_calloc(BUFFER_SIZE + 1, sizeof(char)); if (fd < 0 || BUFFER_SIZE <= 0 || !buffer || !new_line) return (free_null(&buffer, &new_line)); line = ft_strjoin(new_line, buffer, 0); read_bytes = 1; while (!(ft_strchr(buffer, '\n')) && read_bytes > 0) { read_bytes = read(fd, buffer, BUFFER_SIZE); if (read_bytes == 0) break ; if (read_bytes == -1) return (free_null(&buffer, &new_line)); buffer[read_bytes] = '\0'; line = ft_strjoin(line, buffer, 1); } free(buffer); return (finalize_line(&line, &new_line)); }
ft_strjoin实现
char *ft_strjoin(char *s1, char *s2, int flag) { char *aux_s1; int i; int j; if (!s1) s1 = ft_calloc(1, sizeof(char)); if (!s2) s2 = ft_calloc(1, sizeof(char)); aux_s1 = (char *)malloc(ft_strlen(s1) + ft_strlen(s2) + 1); if (!aux_s1) return (0); i = 0; while (s1[i] != '\0') { aux_s1[i] = s1[i]; i++; } j = 0; while (s2[j] != '\0') aux_s1[i++] = s2[j++]; aux_s1[i] = '\0'; if (flag == 1) free(s1); return (aux_s1); }
问题根源分析
main函数的非法操作
循环结束后line已经是NULL,但代码仍执行printf("%s", line);和free(line);,这会导致空指针解引用和无效释放,是直接触发错误的原因。cut_line函数的内存越界
new_line初始大小固定为BUFFER_SIZE+1,当line中剩余字符长度超过该值时,会向new_line内存范围外写入数据,破坏堆结构,后续free操作就会触发无效指针错误。这也是不同BUFFER_SIZE表现不同的原因——当BUFFER_SIZE足够大时,剩余字符不会超出其长度,越界不会发生;反之则会破坏内存。finalize_line函数的逻辑漏洞
当**line == '\0'且!*new_line时,代码释放*line并置为NULL,返回NULL后main循环结束,后续又对NULL执行free,引发错误。
修复方案
1. 修正main函数
移除循环外对line的非法操作,同时补充关闭文件描述符:
int main(void) { int fd; char *line; fd = open("file.txt", O_RDONLY); while ((line = get_next_line(fd)) != NULL) { printf("%s", line); free(line); } close(fd); return(0); }
2. 修复cut_line的内存越界问题
改为动态分配new_line的内存,确保能容纳所有剩余字符:
char *cut_line(char *line, char **new_line) { int i; int rest_len; i = 0; while (line[i] != '\n' && line[i] != '\0') i++; if (line[i] == '\n') i++; // 计算剩余字符长度 rest_len = 0; while (line[i + rest_len] != '\0') rest_len++; // 释放旧空间,重新分配足够内存 free(*new_line); *new_line = ft_calloc(rest_len + 1, sizeof(char)); if (!*new_line) { free(line); return NULL; } // 复制剩余字符 rest_len = 0; while (line[i]) { (*new_line)[rest_len] = line[i]; line[i] = '\0'; rest_len++; i++; } return (line); }
3. 调整finalize_line函数
适配cut_line的参数修改,完善逻辑:
char *finalize_line(char **line, char **new_line) { *line = cut_line(*line, new_line); if (!*line) return NULL; if (**new_line == '\0') { free(*new_line); *new_line = NULL; } if (**line == '\0' && !*new_line) { free(*line); *line = NULL; return (NULL); } return (*line); }
4. 修正get_next_line初始逻辑
调整new_line的初始分配方式,修正循环条件的换行符检查:
char *get_next_line(int fd) { static char *new_line; char *buffer; char *line; int read_bytes; buffer = ft_calloc(BUFFER_SIZE + 1, sizeof(char)); if (!buffer) return (free_null(&buffer, &new_line)); if (!new_line) new_line = ft_calloc(1, sizeof(char)); if (fd < 0 || BUFFER_SIZE <= 0 || !new_line) return (free_null(&buffer, &new_line)); line = ft_strjoin(new_line, "", 0); free(new_line); new_line = NULL; read_bytes = 1; // 检查当前line中是否有换行符,无则继续读取 while (!(ft_strchr(line, '\n')) && read_bytes > 0) { read_bytes = read(fd, buffer, BUFFER_SIZE); if (read_bytes == 0) break ; if (read_bytes == -1) { free(line); return (free_null(&buffer, &new_line)); } buffer[read_bytes] = '\0'; line = ft_strjoin(line, buffer, 1); if (!line) return (free_null(&buffer, &new_line)); } free(buffer); return (finalize_line(&line, &new_line)); }
5. 补充free_null函数实现
确保能正确释放指针并置空:
void *free_null(char **ptr1, char **ptr2) { if (ptr1 && *ptr1) { free(*ptr1); *ptr1 = NULL; } if (ptr2 && *ptr2) { free(*ptr2); *ptr2 = NULL; } return NULL; }
内容的提问来源于stack exchange,提问作者Manuel
相关产品推荐
相关产品推荐

