views:

128

answers:

6

I want to extensively test some pieces of C code for memory leaks.

On my machine I have 4 Gb of RAM, so it's very unlikely for a dynamic memory allocation to fail. Still I want to see the comportment of the code if memory allocation fails, and see if the recover mechanism is "strong" enough.

What do you suggest ? How do I emulate an environment with lower memory specs ? How do i mock my tests ?

EDIT: I want my tests to be code independent. I only have "access" to return values for different functions in the library I am testing. I am not supposed to write "test logic" inside the code I am testing.

+1  A: 

type in *(char*)0; when you want your code to fail or store it in allocated var

(obviously it should be activated/desactivated by some #define setted by makefile)

The idea is to precisely control which malloc you want to fail. I used the previous trick to ensure what would be the behavior of a program I wrote if a segfault ever occured. I was able to check that the exception was caught and that there was no memory leak with allready allocated object.

You can also add some kind of counter to make your alloc return 0 only after a while and check that your code corretly handle this case (and, for instance, correctly free parts of what your program choose to destroy to handle memory starvation).

kriss
How is this helpful ? Can you please be more specific ?
Andrei Ciobanu
when malloc fail that's what it will do, return 0... you can easily fake it. I'm not saying anything more.
kriss
Ok, probably i haven't being descriptive enough. But I want my tests to be code independent.
Andrei Ciobanu
If you are suggesting to have a #define that replaces malloc calls with (char *)0, then this will fail on the very first allocation, which is not very good test.
Laurynas Biveinis
that's not what I'm saying. I'm just stating that you can control malloc behavior by setting 0 in some cases. And you can exactly control which malloc you want to test failing. If you set a global wrapper you will test something, but not something very controlled as any malloc could fail in the lifecycle of the program. It's very like a monkey test. I happened to use the previous trick to see how my program (multithreaded) behave when a segfault occur. So I really voluntarily started some segfaults using previous trick.
kriss
@kriss Sorry, it's hard to understand what exactly you mean. Perhaps you could edit and elaborate your answer?
Laurynas Biveinis
@Laurynas: you'are right, I should put some sample code. I haven't time right now but I'll come back to this.
kriss
+4  A: 

Make a wrapper malloc and free, you can put your own logic there for when it fails and when it doesn't.

Then:

#define malloc(X) (myMalloc(X))
#define free(X) (myFree(X))
#define realloc(X, Y) (myRealloc(X, Y))
#define calloc(X, Y) (myCalloc(X, Y))
#define valloc(X) (myValloc(X))

You can #define and #undef the macros as you want throughout your code.

Brian R. Bondy
+`realloc()` + `calloc()` + `valloc()`
skwllsp
added them for fun
Brian R. Bondy
@Brian: +strdup() and I probably still forgot some more...
kriss
@Brian: ad another problem is that with a really small memory footprint it can also be stack limit that is reached before heap limit. Hence memory starvation does not necessarilly happen on mallocs but could happen at any function call that usually works... :-(
kriss
+1  A: 

disable swap, then at the beginning of your app do while(malloc(1000000));

This will leave the environment with less than 1MB of free memory for the rest of your app to run. Adjust the value for other results.

SF.
+4  A: 

To do this code independently, I'd suggest using a virtual machine with a much smaller memory setting and running your code within that. Otherwise, you are left with testing on actual systems with smaller memory configurations.

Lazarus
+1  A: 

When I had to do this, I made a small program which used up all the memory quickly. Something like this:

// Beware, brain-compiled code ahead: 
#include <stdlib.h>

bool alloc(size_t n)
{
    return NULL != malloc(n);
}

int main()
{
    size_t n = 1;
    for(;;) {
        while( alloc(n) )
            n*=2;
        do
            n/=2;
        while( !alloc(n) );
    }
}

My experience with the NT line of Windows was that, while the OS was rock-solid, just about everything else crashed on me, including the debugger. No fun to work that way.

sbi
+3  A: 

If this is a unix -type of system, then you can do the same thing that jemalloc does. Implement your own malloc, compile it as .so -library and start the test with LD_PRELOAD=yourmalloc.so

You could build in a setting that will allow you to control how it operates:

void tester() {
     your_malloc_allow_allocation(1024*1024*4); // allow 4 more megs of allocation

     librarycall();
     // ... handle errors..

     your_malloc_reset_limits(); // drop limits
}
Pasi Savolainen