Domanda

The following code compiles and execute without any warning or error. However, when I use splint to analyze the code, it shows 4 warnings (shown below the code).

Most of the examples I have seen (with that kind of warnings), uses malloc and free. As this code does not uses malloc, can we say its safe to ignore those warnings? What should be the correct way to code this without removing the pointers?

#include <stdio.h>

typedef struct
{
    void (*Doit) ( void );
} func;

typedef struct
{
    func f;
    int val;
} obj;

typedef struct
{
    obj *o;
} world;

static void Read( void ) {
    printf( "Read\n");
}

static void Init( world *w ) {
    obj pc;
    w->o = &pc;           //(1)
    w->o->val = 10;
    w->o->f.Doit = Read;
    w->o->f.Doit();
}

int main() {
    world w;
    Init( &w );     //(2)
    return 0;      //(3)
}

(1) :28:5: Implicitly only storage w->o (type obj *) not released before assignment: w->o = &pc . A memory leak has been detected. Only-qualified storage is not released before the last reference to it is lost.

(1) :28:5: Immediate address &pc assigned to implicitly only: w->o = &pc . An immediate address (result of & operator) is transferred inconsistently.

(2) :33:11: Variable w used before definition An rvalue is used that may not be initialized to a value on some execution path.

(3) :34:14: Only storage w.o (type obj *) derived from variable declared in this scope is not released (memory leak). A storage leak due to incomplete deallocation of a structure or deep pointer is suspected. Unshared storage that is reachable from a reference that is being deallocated has not yet been deallocated. Splint assumes when an object is passed as an out only void pointer that the outer object will be deallocated, but the inner objects will not.

This code is just a test of something else I want to achieve, but as I'm not proficient in C, I would like to understand the risk of memory leaks using the above approach.

Thanks in advance.

È stato utile?

Soluzione

I find the splint output to be quite unreadable. Depending on your platform, you might also want to try valgrind.

Reglardless, the main issue with your code is that pc is a local variable. It becomes invalid at the end of Init(), as it is (with probably every compilers) located on the stack.

You will probably want to do

w->o = (obj *) malloc(sizeof(obj));

instead.

An alternate way of doing this would be to change the type of o in w to obj instead of obj *.

Note on memory management in C (further reading highly recommended):

Function arguments and local variables usually lie on the so-called stack. They become invalid as soon as the function returns. The size of stack objects always needs to be known to the compiler.

Objects that are allocated via malloc() lie on the heap. malloc() can be used for objects of unknown size. Objects allocated by malloc() stay valid until their pointers are passed to realloc() or free(). If you forget to pass a malloc'd pointer to free, you have a memory leak. If you access an object after it became invalid, you'll get undefined behaviour (that place in the heap might be re-used by something else by now, but maybe the data is still there, who knows?). In the worst case you might get a segmentation fault, or a heap corruption. If you pass an invalid object pointer to free() or realloc(), you'll probably get a heap corruption.

Global variables and static function members lie somewhere else (tm), and valid during the whole execution of the program (at least from entering main until returning from it, like a local variable of main).

malloc() is a complex function that internally manages available blocks of memory in a complex datastructure called the heap. A heap corruption means that you damage that datastructure itself. A segmentation fault means that you write/read somewhere outside of a valid block of memory.

Note that the C standard does not guarantee any if this. It doesn't guarantee that something like a stack even exists. However, all compilers that I know of do it like this. For some embedded platforms though, malloc() is a pretty simple function that just increments a pointer each time something is allocated, and free() does nothing at all.

Altri suggerimenti

In Init()

static void Init( world *w ) {
    obj pc;
    w->o = &pc;           //(1)
    w->o->val = 10;
    w->o->f.Doit = Read;
    w->o->f.Doit();
}

obj pc; is a automatic variable in function Init().

The memory it is pointing will be invalid after retun from Init(). So In main() after Init() w->o will be invalid.

you have use malloc

w->o = (obj *) malloc(sizeof(obj)); 

you can do this in Init() or main().

Note: you have to free this using free() else memory leak will occur.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top