3

Splint does a good job tracking down memory leaks in C code. Every malloc() should have a matching free(). But BoehmGC-collected code uses GC_MALLOC() with no matching GC_FREE(). This makes Splint go crazy with tons of messages about memory leaks that aren't actually there.

Does anyone know the proper annotation for such code so that Splint no longer shows spurious memory leak messages?

In particular, could someone annotate Wikipedia's BoehmGC example?

#include <assert.h>
#include <stdio.h>
#include <gc.h>

int main(void)
{
    int i;

    GC_INIT();
    for (i = 0; i < 10000000; ++i)
    {
        int **p = GC_MALLOC(sizeof(int *));
        int *q = GC_MALLOC_ATOMIC(sizeof(int));

        assert(*p == 0);
        *p = GC_REALLOC(q, 2 * sizeof(int));
        if (i % 100000 == 0)
            printf("Heap size = %zu\n", GC_get_heap_size());
    }

    return 0;
}
madth3
  • 7,275
  • 12
  • 50
  • 74
mcandre
  • 22,868
  • 20
  • 88
  • 147

1 Answers1

2

I think that you should annotate the BoehmGC API itself, and then the annotations needed for the example (if any) will become obvious.

For starters, any pointer returned by a function with no annotation is implicitly @only, which means that you must release the associated memory before reference is lost. Therefore, the first step would be to annotate the allocators so that they no longer return an @only reference. Instead, the manual advises using shared references:

If Splint is used to check a program designed to be used in a garbage-collected environment, there may be storage that is shared by one or more references and never explicitly released. The shared annotation declares storage that may be shared arbitrarily, but never released.

If you didn't want to modify the BoehmGC API, you could work around it by creating properly annotated, wrapper functions. In addition, you would need to disable specific transfer errors within your wrapper functions (because they get an implicit @only reference from the BoehmGC API and then return it as @shared).

For example, this is the way you would disable the "Statement has no effect" error at a given point of your code:

/*@-noeffectuncon@*/
not_annotated_void_function();
/*@=noeffectuncon@*/

The wrapper function would be something like this:

/*@shared@*/ /*@null@*/ /*@out@*/ static void * MY_GC_MALLOC(size_t size) /*@*/{
    /*@-onlytrans@*/
    return( GC_MALLOC(size) );
    /*@=onlytrans@*/
}

Then in the example you'd use MY_GC_MALLOC rather than GC_MALLOC.

Guillermo Calvo
  • 777
  • 6
  • 9
  • Thanks for the well-thought-out response. Could you add one more thing: an implemented wrapper function for the Wikipedia example that reduces Splint warnings? – mcandre Aug 02 '11 at 01:16
  • 1
    Sure, I added an implemented wrapper function to my answer. – Guillermo Calvo Aug 02 '11 at 07:02
  • Almost there (https://github.com/mcandre/boehmtest). Two warnings remain, about undefined pointers. – mcandre Aug 03 '11 at 05:04
  • I suppose that the errors are on lines **48** (`assert(*p == 0);`) and **49** (`*p = SPLINT_GC_REALLOC(q, 2 * sizeof(int));`), am I right? Could you please upload Splint's output to the repo (or at least copy+paste it here) so I can help you out with those? – Guillermo Calvo Aug 03 '11 at 06:15
  • 1
    This is what I meant by "annotating the API itself": you could include [this header file](http://pastebin.com/PhHdZj3q) (instead of the original `gc.h`) and then the example is OK without any annotations. I hope it works for you. – Guillermo Calvo Aug 03 '11 at 22:01
  • Thanks! I sent an email to the Boehm GC mailing list with the annotated code and a link to this SO question. – mcandre Aug 04 '11 at 07:20
  • 1
    Good idea! However, my header file only provides a small fraction of the API (just the tiny bits the example needs). If you wanted to use other GC functionalities (say `GC_REGISTER_FINALIZER`, for example), you'd need to annotate and add it to the header file. I think it is, at least, a good starting point. – Guillermo Calvo Aug 04 '11 at 08:18