Search code examples
cmallocvalgrind

My own substring function | valgrind showing some malloc errors I do not understand


Task:

Allocate (with malloc(3)) and return a substring from the string s. The substring begins at index start and is of maximum size len.

Return value: The substring. NULL if the allocation fails.

Hello, after a few hours I decided to ask for some clarifications. I have the following functions and some error from Valgrind I can't understand, that shows up even if everything is correct. (ft_strlen(s) I call from my own library, where also lib for malloc is put).

char    *ft_substr(char const *s, unsigned int start, size_t len)
{
    unsigned int x;
    char        *a;
    unsigned int i;

    i = 0;
    if (s == NULL)
        return (0);
    if (start > ft_strlen(s))
    {   
        if (!(a = (char *)malloc(0*sizeof(char))))
            return (0);
        return (a);
    }
    if ((start + len) < ft_strlen(s))
        x = len;
    else
        x = ft_strlen(s) - start;
    if (!(a = (char *)malloc((x + 1) * sizeof(char))))
        return(0);
    while (i < x)
    {
        a[i] = s[start + i];
        i++;
    }
    a[i] = '\0';
    return (a);
}

I left there one error on purpose. If I am suppose to return null if allocation fails, why below instead of 0 should be 1? Anyway it does not change the errors presented below.

if (!(a = (char *)malloc(0 * sizeof(char))))

ERRORS:

==4817== Invalid read of size 1
==4817==    at 0x483FED4: strcmp (in /usr/lib/x86_64-linux-gnu/valgrind vgpreload_memcheck-amd64-linux.so)
==4817==    by 0x4039BC: main (ft_substr_test.cpp:28)
==4817==  Address 0x4dad0d0 is 0 bytes after a block of size 0 alloc'd
==4817==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4817==    by 0x403B58: ft_substr (in /home/tony/42cursus/0lvl_libft_1week/libftTester/a.out)
==4817==    by 0x4039A4: main (ft_substr_test.cpp:27)
==4817==

Solution

  • Your function has multiple problems:

    • the type of start, x and i should be size_t.
    • malloc(0) has implementation defined behavior. You should allocate at least 1 byte for the null terminator and set it before returning the pointer to the empty string or return NULL if the specification says you should.
    • the function should call ft_strlen() just once.
    • the special case for start > ft_strlen(s) can be handled in the general case if an empty string should be returned.

    Here is a modified version:

    char *ft_substr(char const *s, size_t start, size_t len) {
        size_t i, slen;
        char *a;
    
        if (s == NULL) {
            return NULL;
        }
        slen = ft_strlen(s);
        if (start > slen) {
            start = slen;
        }
        if (len > slen - start) {
            len = slen - start;
        }
        if (!(a = malloc((len + 1) * sizeof(char)))) {
            return NULL;
        }
        for (i = 0; i < len; i++) {
            a[i] = s[start + i];
        }
        a[i] = '\0';
        return a;
    }
    

    PS: you may need to reformat the code to fit the local 42 norminette...