In get_line, I noticed:
Code:
line = ft_substr(*s, 0, i);
tmp = *s;
*s = ft_substr(tmp, i, ft_strlen(tmp) - i);
free(tmp);
return (line);
ft_substr returns a string allocated by malloc. The string input to get_line is from read_line, which itself calls a function that uses malloc.
So, what you have here are a net of three malloc calls and only one call to free. It's possible that the caller of get_next_line is responsible for calling free, but that still leaves one unmatched call to malloc, and thus a memory leak. It's not a big deal because a subsequent call to get_next_line will normally call free, but the very last call will leave it allocated until the end of the program. Perhaps a solution is to call free in get_next_line before returning a null pointer when it is clear that there's nothing more to read yet the buffer is empty.
EDIT:
I originally posted this thinking that your friend mixed up using s versus using the return value of get_line as the return value of get_next_line, then I realised that s was being used to save the unused portion of the buffer. Your friend probably should use a more descriptive variable name.
One of the malloc calls can be eliminated by simply inserting a null character at the right place instead of calling ft_substr. The corresponding free will be removed though, so this does not fix the memory leak.
Also, instead of joining strings by finding the end of the first string from the start, it's more efficient to just join the second string starting from the end of the first, since your friend is already computing the string lengths so the location of the end of the first is already known.