Unit test C library, memory management

I am working on a fairly large C library, which currently has no tests. As the API begins to be final, I would like to start writing unit tests.

Almost all my functions act on the first parameter (structure).

The naive approach to unit test is to have the structure of the preliminary function call in a known state, call the function, and then compare the structure of the preliminary call with the expected result.

Now this works with a structure consisting of scalar types, but as for allocated memory, I was wondering what approach you used.

For example, imagine the image structure when you do:

CreateImage(&img, x, y); 

you expect img-> x to be x, img-> y to be y and img-> pixels, a pointer to something big enough to hold x * y * sizeof(pixel) .

Checking the first two is trivial, but what about img-> pixels? I don't want to check if the malloc call was successful, since I can overload malloc, but I want to know if malloc was called correctly.

This is especially important in the case of:

 CreateImage(*img, x, y) { img->x = x; img->y = y; /* do something, dhoo, that something is broken and modify x or y */ img->pixels = malloc(x * y * sizeof(pixel)); /* wrong allocation size */ if(!img->pixels) error("no memory"); } 

Hope my question is clear.

Thanks.

+1
source share
3 answers

In your unit test, you overloaded the malloc function to register the value with which it was called (for example, alloc_size ).

Then just check that they are all correct:

  • alloc_size % sizeof(pixel) == 0
  • alloc_size % x == 0
  • alloc_size % y == 0
  • ((alloc_size / sizeof(pixel)) / x ) / y == 1

Don't just copy the code from the function you are testing, i.e. multiplication - because you can end up reproducing the error.

In this case, you can potentially replicate the error - if there are no tests of restrictions on x and y , then multiplication in the malloc call is an error in itself (think about what happens on a system with 32 bits size_t , sizeof(pixel) == 4 , x == 40000 and y == 40000 ).

+2
source

You can overload malloc to set a series of expectations on it. Since you know, before making a call, how much memory he needs to allocate, you could have something like that.

 SetMallocExpectation(x * y * sizeof(pixel)); CreateImage(&img, x, y); if ( InvalidMalloc() ) { // The malloc call was with a different size } ResetMalloc(); 

As for the implementation, I believe it will look something like this.

 size_t mallocExpectations[SOME_SIZE]; int mallocCur = 0; int mallocError = 0; int numExpectations = 0; void* MyMalloc(size_t size) { if ( size != mallocExpectations[mallocCur++] ) { mallocError = 1; } return (*malloc)(size); } void SetMallocExpectation(size_t size) { mallocExpectations[numExpectations++] = size; } int InvalidMalloc() { return mallocError; } void ResetMalloc() { mallocCur = 0; mallocError = 0; curExpecations = 0; } 
+1
source

Another idea is to try to fill the buffer created by malloc with the maximum size, and then run the test package using Valgrind. This should have problems with the distribution of the surface. Running it with Valgrind is also useful for other things, such as detecting memory leaks.

+1
source

All Articles