【问题标题】:Valgrind finds a leak in my code, could anybody help me find it?Valgrind 在我的代码中发现了漏洞,有人可以帮我找到吗?
【发布时间】:2017-12-08 17:49:04
【问题描述】:

我有以下函数代码。 它读取一个文件,每行一行,事先不知道大小。

这是我学校的一项学习活动。我已经在上面运行了 valgrind 命令,我得到了这个输出(完整的日志在这里 => valgrind log):

==21166== 44 bytes in 1 blocks are definitely lost in loss record 14   of 42
==21166==    at 0x1000CB606: malloc (in /Users/cbaillat/.brew/Cellar/valgrind/3.13.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==21166==    by 0x100000F0C: ft_strnew (in ./get_next_line)
==21166==    by 0x10000061C: get_next_line (get_next_line.c:71)
==21166==    by 0x10000058A: main (main.c:31)

我不知道那是从哪里来的。这是引发泄漏的函数:

#include "get_next_line.h"

/*
** If newline is null, it means it hasn't found a new line in the string.
** It means we have reach the end of line.
*/

static int  ft_copy_leftover(char **line, char fd_buffer[BUFF_SIZE], char *nl)
{
    if (nl == NULL)
        return (1);
    ft_strcpy(fd_buffer, &nl[1]);
    (*line)[nl - (*line)] = '\0';
    return (1);
}

/*
** 1- We keep reading unless we find a new line or we reach the end of file
** 2- We reallocate the old pointer with buffer size
** 3- As long as there are characters to read and we haven't encountered a
**  new line, we keep copying the data into line
**  We store the buffer in line, and then erase it
** 4- If we have already reached the end of file, we do not need to copy the
**  buffer. Otherwise we copy it to line.
*/

static int  read_line(const int fd, char fd_buffer[BUFF_SIZE], char **line)
{
    int32_t     status;
    char        *newline;
    uint32_t    len;

    while (((newline = ft_strchr(*line, '\n')) == NULL)
        && ((status = read(fd, fd_buffer, BUFF_SIZE)) > FILE_READ))
    {
        len = ft_strlen(*line) + 1;
        if ((*line = ft_realloc(*line, len, len + BUFF_SIZE)) == NULL)
            return (ERROR);
        ft_strcat(*line, fd_buffer);
        ft_bzero(fd_buffer, BUFF_SIZE);
    }
    if ((**line != '\0') && (status >= FILE_READ))
        return (ft_copy_leftover(line, fd_buffer, newline));
    return (status);
}

/*
** 1- If the buffer is not empty, we allocate a new string and copy the buffer
**  contents
** 2- We loop in the buffer in case we have multiple new lines inside
*/

int         get_next_line(const int fd, char **line)
{
    static char fd_array[ULIMIT_N][BUFF_SIZE + 1];
    int8_t      status;

    if (fd < 0 || fd > ULIMIT_N || line == NULL
        || !(*line = ft_strnew(BUFF_SIZE + 1)))
        return (ERROR);
    if (fd_array[fd][0] != '\0')
        *line = ft_strcpy(*line, fd_array[fd]);
    ft_bzero(fd_array[fd], BUFF_SIZE + 1);
    status = read_line(fd, fd_array[fd], line);
    return (status);
}

函数 'ft_strnew' 只是为一个字符串分配内存并将其设置为 0:

#include "libft.h"

char    *ft_strnew(size_t size)
{
    char    *str;

    if ((str = (char *)malloc(sizeof(*str) * (size + 1))) == NULL)
        return (NULL);
    ft_memset((void *)str, (int)'\0', (size + 1));
    return (str);
}

谁能帮我找到它? 顺便说一句,这就是我在 main 中调用我的函数的方式:

int main(int ac, char **av)
{
    int32_t i;
    int32_t fd;
    int32_t status;
    char    *line_read;

    if (ac <= 1)
        return (0);
    fd = open(av[1], O_RDONLY);
    i = 0;
    line_read = NULL;
    while (1)
    {
        status = get_next_line(fd, &line_read);
        // printf("status: %d\n", status);
        if (status == ERROR)
            return (ERROR);
        if (status == FILE_READ)
            return (SUCCESS);
        ft_putstr(line_read);
        free (line_read);
    }
    return (SUCCESS);
}

我每次调用函数时都会释放 malloc 行 (ft_strnew),所以我很茫然。如果您需要更多信息来提供帮助,我很乐意提供。这是我在堆栈上的第一个问题,我希望它足够清楚。

谢谢大家!

编辑:

在返回一些值时,我只是忘记释放主循环中的行。添加几个免费的解决了我的问题!谢谢大家!

while (1)
    {
        status = get_next_line(fd, &line_read);
        // printf("status: %d\n", status);
        if (status == ERROR)
        {
            free (line_read);
            return (ERROR);
        }
        if (status == FILE_READ)
        {
            free (line_read);
            return (SUCCESS);
        }
        ft_putstr(line_read);
        free (line_read);
    }

【问题讨论】:

  • *line = ft_strcpy(*line, fd_array[fd]); 看起来很可疑。
  • 我没有修改指针,也没有 malloc 函数中的任何内容。我的轻微泄漏可能是因为我在一些退货之前没有释放,但我只能在星期一检查。谢谢!

标签: c memory-leaks valgrind


【解决方案1】:

在您的 ft_strnew 函数中,您 malloc 一个新字符串,但您从未释放它。 我建议您在 get_next_line 函数中返回状态之前释放线路!

【讨论】:

  • 但我不能,这个 strnew 被返回给调用它的函数(带有一个 char **指针)。它在我的循环中的主函数中被释放。
  • 在某些情况下,您将退出主函数而不先释放 line_read,在返回之前尝试释放!
  • 谢谢,我没注意到!我会在星期一试试!
【解决方案2】:

有几种可能性。首先在您的while 循环中,如果您获得status 的某些值,您将退出而不释放line_read。但这只会导致丢失一个块。

其次,用这段代码覆盖*line 的值

*line = ft_strcpy(*line, fd_array[fd])

如果您在其中分配更多内存,这看起来是最有可能的候选者。如果您将其更改为该块中的不同点,则在尝试释放它时会遇到完全不同的错误。

【讨论】:

  • 谢谢你,克里斯,大概就是这样!在星期一之前我无法访问我的 gitrepo,但我会测试它并接受你的答案,如果它有效!干杯:)
猜你喜欢
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 2019-09-10
相关资源
最近更新 更多