-3

I have the following code:

static const char * path[2];


int main(int argc, char *argv[]) {
    // validate argument

    char * temp = dirname(dirname(strdup(argv[optind])));
    path[0] = temp
    path[1] = NULL;

    // do stuff

    free(temp);
    return 0;
}

I understand that strdup allocates memory which needs to be freed in order to avoid memory leaks. I attempt to do this before returning from the function but the leak still presists.

Valgrind output:

$ valgrind --leak-check=full -s ./tstprog meta_schema.schema 
==36849== Memcheck, a memory error detector
==36849== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==36849== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==36849== Command: ./tstprog meta_schema.schema
==36849== 
==36849== Invalid free() / delete / delete[] / realloc()
==36849==    at 0x484827F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==36849==    by 0x11577A: main (tstprog.c:134)
==36849==  Address 0x4a42ae1 is 0 bytes inside data symbol "dot.0"
==36849== 
==36849== 
==36849== HEAP SUMMARY:
==36849==     in use at exit: 19 bytes in 1 blocks
==36849==   total heap usage: 255 allocs, 255 frees, 64,111 bytes allocated
==36849== 
==36849== 19 bytes in 1 blocks are definitely lost in loss record 1 of 1
==36849==    at 0x4845899: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==36849==    by 0x49240CF: strdup (in /usr/lib/libc.so.6)
==36849==    by 0x1155C1: main (tstprog.c:108)
==36849== 
==36849== LEAK SUMMARY:
==36849==    definitely lost: 19 bytes in 1 blocks
==36849==    indirectly lost: 0 bytes in 0 blocks
==36849==      possibly lost: 0 bytes in 0 blocks
==36849==    still reachable: 0 bytes in 0 blocks
==36849==         suppressed: 0 bytes in 0 blocks
==36849== 
==36849== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==36849== 
==36849== 1 errors in context 1 of 2:
==36849== Invalid free() / delete / delete[] / realloc()
==36849==    at 0x484827F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==36849==    by 0x11577A: main (tstprog.c:134)
==36849==  Address 0x4a42ae1 is 0 bytes inside data symbol "dot.0"
==36849== 
==36849== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

I have also looked at this post and they seem to do the same thing when they call free(who->name).

What am I missing?

ikegami
  • 367,544
  • 15
  • 269
  • 518
User3952
  • 7
  • 2
  • 6
    This program ***does not*** call `free()` on the pointer returned by `strdup()`. It calls `free()` on one returned by `dirname(dirname(strdup(...)))`. There is no particular reason to expect that `dirname()` returns its argument. In fact, [its docs](https://linux.die.net/man/3/dirname) specifically say it "may return [a] pointer[] to statically allocated memory which may be overwritten by subsequent calls." The "invalid free" error from valgrind suggests that your `dirname()` indeed does so. – John Bollinger Nov 28 '22 at 22:38
  • 2
    Note that that also means that chaining `dirname()` calls like you demonstrate might not be safe. – John Bollinger Nov 28 '22 at 22:43

1 Answers1

3

Quoting from dirname man page

   Both dirname() and basename() return pointers to null-terminated strings.  
   (Do not pass these pointers to free(3).)

You are not freeing strdup result (which you can, indeed). You are freeing dirname result. Which you can't.

chrslg
  • 9,023
  • 5
  • 17
  • 31