0

I did a project where the goal was to read a line of a file at each call of a function(get_nl).
A line is all the characters before a "\n".
I attempted to do it with linked lists to be able to read multiple files at the same time.

But it seems to be leaking memory and I don't really know how or from where. I used valgrind you can check the output just below.

I just used the flag --leak-check=full

==30653== Memcheck, a memory error detector
==30653== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==30653== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==30653== Command: ./a.out
==30653== Parent PID: 20837
==30653== 
==30653== Syscall param open(filename) points to unaddressable byte(s)
==30653==    at 0x10062D862: open (in /usr/lib/system/libsystem_kernel.dylib)
==30653==    by 0x100000D11: main (get_next_line.c:145)
==30653==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==30653== 
==30653== 
==30653== HEAP SUMMARY:
==30653==     in use at exit: 22,577 bytes in 167 blocks
==30653==   total heap usage: 188 allocs, 21 frees, 31,025 bytes allocated
==30653== 
==30653== 72 bytes in 3 blocks are possibly lost in loss record 26 of 43
==30653==    at 0x1000AC6EA: calloc (in /usr/local/Cellar/valgrind/3.15.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==30653==    by 0x1007567E2: map_images_nolock (in /usr/lib/libobjc.A.dylib)
==30653==    by 0x1007697DA: objc_object::sidetable_retainCount() (in /usr/lib/libobjc.A.dylib)
==30653==    by 0x100007C64: dyld::notifyBatchPartial(dyld_image_states, bool, char const* (*)(dyld_image_states, unsigned int, dyld_image_info const*), bool, bool) (in /usr/lib/dyld)
==30653==    by 0x100007E39: dyld::registerObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*)) (in /usr/lib/dyld)
==30653==    by 0x10022171D: _dyld_objc_notify_register (in /usr/lib/system/libdyld.dylib)
==30653==    by 0x100756075: _objc_init (in /usr/lib/libobjc.A.dylib)
==30653==    by 0x1001ABB34: _os_object_init (in /usr/lib/system/libdispatch.dylib)
==30653==    by 0x1001ABB1B: libdispatch_init (in /usr/lib/system/libdispatch.dylib)
==30653==    by 0x1000BA9C2: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==30653==    by 0x100019AC5: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==30653==    by 0x100019CF5: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==30653== 
==30653== LEAK SUMMARY:
==30653==    definitely lost: 0 bytes in 0 blocks
==30653==    indirectly lost: 0 bytes in 0 blocks
==30653==      possibly lost: 72 bytes in 3 blocks
==30653==    still reachable: 200 bytes in 6 blocks
==30653==         suppressed: 22,305 bytes in 158 blocks
==30653== Reachable blocks (those to which a pointer was found) are not shown.
==30653== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==30653== 
==30653== For lists of detected and suppressed errors, rerun with: -s
==30653== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 12)

Here's my code below :

My helper functions :

#include "header.h"

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

    i = 0;
    while (s[i] != c)
    {
        if (!(s[i]))
            return (NULL);
        i++;
    }
    return ((char *)s + i);
}

size_t  ft_strlen(const char *s)
{
    size_t  i;

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

size_t  ft_strnlen(const char *s, size_t len)
{
    size_t  i;

    i = 0;
    while (i < len && *s)
        i++;
    return (i);
}

void    ft_strdel(char **alst)
{
    free(*alst);
    *alst = NULL;
}

char    *ft_strndup(const char *s, size_t n)
{
    char    *str;
    size_t  i;

    i = -1;
    if (!(str = (char *)malloc(sizeof(char) * ft_strnlen(s, n) + 1)))
        return (NULL);
    while (++i < n)
        str[i] = s[i];
    str[i] = '\0';
    return (str);
}

My core functions

#include "header.h"
#include <fcntl.h>

void    *ft_memalloc(size_t size)
{
    char    *str;
    size_t  i;

    i = 0;
    if (!(str = (char *)malloc(sizeof(char) * (size))))
        return (NULL);
    while (i < size)
    {
        str[i] = 0;
        i++;
    }
    return (str);
}

t_list  *ft_is_allocated(t_list **alst, const int fd)
{
    t_list  *temp;

    if (!(*alst))
    {
        if (!((*alst) = ft_memalloc(sizeof(t_list))))
            return (NULL);
        (*alst)->fd = fd;
    }
    temp = (*alst);
    while (temp->next != NULL && temp->fd != fd)
        temp = temp->next;
    if (temp->next == NULL && temp->fd != fd)
    {
        if (!(temp->next = ft_memalloc(sizeof(t_list))))
            return (NULL);
        temp->next->fd = fd;
        temp = temp->next;
        temp->next = NULL;
    }
    return (temp);
}

int     ft_newline(char **str, char **line, int r)
{
    char            *pos;
    char            *tmp;
    size_t          i;

    if (*str == NULL && r == 0)
        return (0);
    if ((pos = ft_strchr((*str), '\n')) == NULL && r == 0 && *str)
    {
        if (ft_strlen(*str) == 0)
        {
            *line = ft_strndup("", 0);
            return (0);
        }
        if (!(*line = ft_strndup((*str), ft_strlen(*str))))
            return (-1);
        ft_strdel(str);
        return (0);
    }
    i = (pos - *str);
    if (!(*line = ft_strndup((*str), i))
        || !(tmp = ft_strndup(&(*str)[i + 1], ft_strlen(&(*str)[i + 1]))))
        return (-1);
    free((*str));
    (*str) = tmp;
    return (1);
}

char    *ft_strjoin(char const *s1, char const *s2, int tofree)
{
    char    *s;
    size_t  i;
    size_t  j;
    size_t  size;

    i = -1;
    j = -1;
    if (s1 == NULL || s2 == NULL)
        return (NULL);
    size = ft_strlen(s1) + ft_strlen(s2);
    if (!(s = (char *)malloc(sizeof(char) * size + 1)))
        return (NULL);
    while (s1[++i])
        s[i] = s1[i];
    while (s2[++j])
        s[i + j] = s2[j];
    s[i + j] = '\0';
    if (tofree & 1)
        free((char *)s1);
    if (tofree & 2)
        free((char *)s2);
    return (s);
}

int     get_nl(int fd, char **line)
{
    int             r;
    char            buf[BUFFER_SIZE + 1];
    static t_list   *head;

    if (BUFFER_SIZE < 1 || fd < 0 || read(fd, buf, 0) ||
        !(head = ft_is_allocated(&head, fd)) || !line)
        return (-1);
    while ((r = read(fd, &buf, BUFFER_SIZE)) > 0)
    {
        buf[r] = '\0';
        if (head->tmp == NULL)
            head->tmp = ft_strndup(buf, ft_strlen(buf));
        else
            head->tmp = ft_strjoin(head->tmp, buf, 1);
        if (ft_strchr(head->tmp, '\n'))
            return (ft_newline(&(head->tmp), line, r));
    }
    return (ft_newline(&(head->tmp), line, r));
}

int     main(int ac, char **av)
{
    int     fd;
    char    *line;
    int     r;
    (void)  ac;


    line = NULL;
    r = 0;
    fd = open(av[1], O_RDONLY);
    r = get_next_line(fd, &line);
    free(line);
}

My header file :

#ifndef HEADER_H
# define HEADER_H

# include <stdlib.h>
# include <unistd.h>
# include <stdio.h>

typedef struct      s_list
{
    int             fd;
    char            *tmp;
    struct s_list   *next;
}                   t_list;

t_list              *ft_is_allocated(t_list **alst, const int fd);
int                 ft_newline(char **str, char **line, int r);
int                 get_nl(const int fd, char **line);

void                *ft_memalloc(size_t size);
char                *ft_strchr(const char *s, int c);
size_t              ft_strlen(const char *s);
size_t              ft_strnlen(const char *s, size_t len);
void                ft_strdel(char **as);
char                *ft_strndup(const char *s, size_t n);
char                *ft_strjoin(char const *s1, char const *s2, int tofree);

#endif

EDIT :

I don't know how I got the definitely lost but it doesn't show up anymore and I added the debug flag -g3

4

0 回答 0