1

i recently learnt about memalloc() and free() and i was just wondering if there was a way to appropriately check if all the memallocs are appropriately being freed?

I have this code right here for an implementation of doubly linked list, and im unclear whether id need to go through every node and deallocate each p1 and p2, or does doing it once count?:

struct s {
    int data;
    struct s *p1;
    struct s *p2;
};

void freedl(struct s *p)
{
    if(p->p1 != NULL)
    {
        printf("free %d \n", p->p1->data);
    }

    if(p->p2 != NULL)
    {
        freedl(p->p2);
    }
    else
    {
        printf("free last %d", p->data);
        free(p);
    }

}

int main(void) {

    struct s *one, *two, *three, *four, *five, *six;

    one = malloc(sizeof *one);
    two = malloc(sizeof *two);
    three = malloc(sizeof *three);
    four = malloc(sizeof *four);
    five = malloc(sizeof *five);
    six = malloc(sizeof *six);

    one->data = 1;
    one->p1 = NULL;
    one->p2 = two;

    two->data = 2;
    two->p1 = one;
    two->p2 = three;

    three->data = 3;
    three->p1 = two;
    three->p2 = four;

    four->data = 4;
    four->p1 = three;
    four->p2 = five;

    five->data = 5;
    five->p1 = four;
    five->p2 = six;

    six->data = 6;
    six->p1 = five;
    six->p2 = NULL;

    freedl(one);

    return EXIT_SUCCESS;
}

and I'd just like to make sure I'm doing it right!

Gwen Wong
  • 357
  • 3
  • 15

3 Answers3

2

The answer is "yes"; exactly how hard it is depends on what OS you're in.

If you're in Linux, Mac OS X or one of the BSDs (FreeBSD, OpenBSD, ...):

(and possibly Haiku)

You can use an utility called valgrind. It is an excellent utility, designed for (among other things) exactly that --- checking for memory leaks.

The basic usage is simple:

valgrind ./my-program

It is a complex utility though, so I'd recommend checking out the valgrind manual for more advanced usage.

It actually does a far more than that, in that it can detect many (but not all) out-of-bounds accesses and similar problems. It also includes other tools that may come useful, such as callgrind for profiling code.

Do note, however, that valgrind will make your program run very slowly, due to the way it operates.

Any other OS (incl. Windows):

Unfortunately, there is no such utility for Windows (no free ones, anyways; and the commercial ones costed a small fortune, last I've checked --- and none does quite as much as valgrind & friends can).

What you can do, however, is implement macros and check manually on exit:

#define malloc(size) chk_malloc(size, __FILE__, __LINE__)
#define free(ptr)    chk_free(ptr, __FILE__, __LINE__)
// etc... for realloc, calloc

...

// at start of main():
atexit(chk_report); // report problems when program exits normally

You then have to implement chk_malloc, chk_free and so on. There can be some "leaks", however, if you do things such as setAllocator(malloc). If you're okay with losing line information, you can then try doing:

#define malloc chk_malloc // chk_malloc now only takes 1 argument
#define free   chk_free
...

There are certain hacks which would allow you to keep file/line info even with this #define, but they would seriously complicate matters (it would involve basically hacking closures into C).

If you don't want to change the code in any way, you could try your luck with replacing just those functions (by replacing the stdlib with your own shim DLL), though you won't get file/line information that way. It might also be problematic if the compilation was done statically, or if the compiler has replaced it with some intrinsic (which is unlikely for malloc, but not inconceivable).

The implementation can be very simple, or it can be complex, it's up to you. I don't know of any existing implementations, but you can probably find something online.

Community
  • 1
  • 1
Tim Čas
  • 10,501
  • 3
  • 26
  • 32
  • Are there no malloc hooks on windows? – doron Feb 10 '15 at 13:57
  • @doron: That's what I meant by the "any other OS" thing. Anyways, I've expanded a bit to mention the commercial solutions. – Tim Čas Feb 10 '15 at 13:58
  • 2
    @doron: MSVC offers a [CRT debug heap](https://msdn.microsoft.com/en-us/library/974tc9t1.aspx) which you may enable. It's not Valgrind but it's certainly better than nothing – doynax Feb 10 '15 at 14:04
  • @doynax: Yes, that might help; although if you can't use MSVC (say, because of its shoddy support for C), you're still stuck with hacks like these. – Tim Čas Feb 10 '15 at 14:08
  • 1
    @Tim Čas: In any event I find the real headache to be hooking all of the custom allocators which everyone and their grandmothers insist on using. Unfortunately overloading `malloc` with context information does little good when you're passing off an allocator function pointer to a library, through which it grabs a large chunk of memory to subdivide into internal allocations. – doynax Feb 10 '15 at 14:22
  • @doynax: No solution is perfect; even Valgrind won't catch that sort of stuff (though Valgrind will catch out-of-bounds accesses, and *both* solutions will catch if the memory is not freed at the end). – Tim Čas Feb 10 '15 at 14:24
  • @Tim Čas: Valgrind has `VALGRIND_MEMPOOL` hooks to do that sort of thing. It's just that virtually no-one bothers with them and manually integrating these things is hard work if your coding style is "library-happy". – doynax Feb 10 '15 at 14:33
1

System allocators have some way of getting statistics (such as bytes allocated) out of them. (mallinfo on linux). At the beginning of your program you should store the number of bytes allocated and at the end you need t make sure the number is the same. If the number is different, you have a potential memory leak.

Finding that leak is another story. Tools like valgrind will help.

doron
  • 27,972
  • 12
  • 65
  • 103
0

You can valgrind but it can be a little bit slow Or something buildin in compiler. For example in clang (I think that in gcc 4.9 too) there are LeakSanitizer:

$ cat example.c
int main()
{
    malloc(100);
    return 0;
}

$ clang -fsanitize=leak -g example.c -fsanitize=address
$ ASAN_OPTIONS=detect_leaks=1  ./a.out

=================================================================
==9038==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 100 byte(s) in 1 object(s) allocated from:
    #0 0x46c871 (/home/debian/a.out+0x46c871)
    #1 0x49888c (/home/debian/a.out+0x49888c)
    #2 0x7fea542e4ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)

SUMMARY: AddressSanitizer: 100 byte(s) leaked in 1 allocation(s).
KonK
  • 290
  • 1
  • 8