Search code examples
cmemory-leaks

get_next_line function memory leaks (c)


The tester I am using shows that there are leaks all over the place, for instance with the memory allocated by ft_strdup.

When i go up the chain of functions I am under the impression that in any scenario ft_strdup is called, the result will be returned by each function until the end of get_next_line without any opportunity to free it.

char    *get_next_line(int fd)
    {
        static char *leftover;
        char        *next_line;

    if (BUFFER_SIZE <= 0 || !fd)
        return (NULL);
    if (!leftover)
        leftover = ft_read_from_file(fd, leftover);
    if (!leftover)
        return (NULL);
    next_line = ft_find_line(leftover);
    leftover = ft_strchr(leftover, '\n');
    if (leftover)
        leftover++;
    return (next_line);
}

char    *ft_read_from_file(int fd, char *leftover)
{
    char        *buffer;
    long long   bytes_read;

    buffer = malloc(sizeof(char) * (BUFFER_SIZE + 1));
    if (!buffer)
        return (NULL);
    bytes_read = read(fd, buffer, BUFFER_SIZE);
    if (bytes_read < 1)
    {
        free(buffer);
        return (NULL);
    }
    else
        buffer[bytes_read] = '\0';
    leftover = ft_strjoin(leftover, buffer);
    free(buffer);
    return (leftover);
}

char    *ft_find_line(char *leftover)
{
    char    *str;
    int     i;
    int     j;

    j = 0;
    i = 0;
    while (leftover[i] != '\n' && leftover[i])
        i++;
    str = malloc(sizeof(char) * (i + 2));
    while (i > j)
    {
        str[j] = leftover[j];
        j++;
    }
    if (leftover[j] == '\n')
    {
        str[j] = leftover[j];
        j++;
    }
    str[j] = '\0';
    return (str);
}

char    *ft_strchr(const char *s, int c)
{
    int i;

    i = 0;
    while (s[i] && s[i] != (char)c && i < BUFFER_SIZE)
        i++;
    if (s[i] == (char)c)
        return ((char *)&s[i]);
    return ((void *)0);
}

char    *ft_strjoin(char const *s1, char const *s2)
{
    int     i;
    int     j;
    char    *str;

    i = 0;
    j = 0;
    if (!s1 && !s2)
        return (NULL);
    if (!s1)
        return (ft_strdup(s2));
    str = malloc((ft_strlen(s1) + ft_strlen(s2) + 1) * sizeof(char));
    if (str == NULL)
        return (NULL);
    while (s1[i])
    {
        str[j++] = s1[i++];
    }
    i = 0;
    while (s2[i])
    {
        str[j++] = s2[i++];
    }
    str[j] = '\0';
    return (str);
}

char    *ft_strdup(const char *s1)
{
    int     i;
    int     size;
    char    *ptr;

    i = 0;
    size = ft_strlen(s1);
    ptr = malloc(sizeof(char) * size + 1);
    if (ptr == NULL)
        return (NULL);
    while (s1[i])
    {
        ptr[i] = s1[i];
        i++;
    }
    ptr[i] = '\0';
    return (ptr);
}

int ft_strlen(const char *str)
{
    int i;

    i = 0;
    while (str[i])
        i++;
    return (i);
}

Solution

  • You malloc() a string in ft_read_from_file() and you use strchr() with the malloc ptr.

    Here a minimal example :

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    int main(void)
    {
            char * ptr;
    
            ptr = malloc(sizeof(char) * 5);
            strcpy(ptr, "test");
    
            printf("%p\n", ptr);
            ptr = strchr(ptr, 's');
            printf("%p\n", ptr);
            free(ptr); // free(): invalid pointer
            return (0);
    }
    

    Also why if (BUFFER_SIZE <= 0 || !fd) ?

    0 is a valid file descriptor and you probably need to handle it.

    Also is not really a good way to check the BUFFER_SIZE.

    Here another way :

    # if BUFFER_SIZE <= 0
    #  error "BUFFER_SIZE can't be <= 0"
    # endif