views:

236

answers:

5

my function:

struct hostent * gethost(char * hostname){
    if(/*some condition under which I want 
         to change the mode of my program to not take a host*/){
       return null
    }
    else{
        struct hostent * host = gethostbyname(hostname);
        return host;
    }
}

in main:

struct hostent * host = gethost(argv[2]);

(ignore any minor errors in the code, I'm spewing from memory)

this works fine. and Valgrind doesn't tell me I'm losing memory, despite the fact I'm not freeing.

Why? I thought stuff allocated on the stack disappears with the function call returning? or is it because I return the pointer? is this dangerous in any way?

+10  A: 

host is not allocated on the stack, only a pointer to it is on the stack. The pointer gets copied when the function returns, so there is nothing wrong with the code.

Note that gethostbyname does not actually dynamically allocate memory. It always returns a pointer to the same statically allocated block of memory, which is why valgrind doesn't report a leak. Be careful, though, because that means you have to copy the hostent returned by your function if you want to save the value for later because further calls to gethost will overwrite it.

Gabe
Ah thanks a lot. So it's unique to `gethostbyname`? if I did this for a `char *`, for example, the values in that array might be overwritten later?My program only has to deal with one host per run, so this should be fine.
piggles
Whether the value pointed to by a pointer gets overwritten on later calls depends on the function you're calling. For any C standard library function that returns a pointer that you do not pass in, you can assume it's returning a pointer to static memory and it can get overwritten.
Gabe
A: 

Well the memory is not leaked until all references to it is lost, in your example the pointer is returned so there is still a reference to it.

However imho it's a bad design decision on most cases to rely on another part of the code to release dynamic memory. If the function needs to return a struct for example, the caller should do it and pass a pointer to the struct.

monoceres
The memory is not leaked because `gethostbyname` doesn't do dynamic allocation. It returns a static pointer every time.
Gabe
And who, pray tell, tracks references on this pointer? :)
vladr
Nobody tracks references to the pointer. The block of memory is allocated when the socket library loads and is not deallocated until the process ends or the socket library is unloaded.
Gabe
+2  A: 

from the manual :

RETURN VALUE
       The gethostbyname() and gethostbyaddr() functions  return  the  hostent
       structure  or a NULL pointer if an error occurs.  On error, the h_errno
       variable holds an error number.  When non-NULL, the  return  value  may
       point at static data, ...

Some memory is reserved at the compile time (ie. inside the binary the code) for the structure, the function returns a pointer to this memory.

Ben
+3  A: 

It's fine and does leak because the returned pointer doesn't point to data on stack or heap, but some static variable.

http://linux.die.net/man/3/gethostbyname:

The functions gethostbyname() and gethostbyaddr() may return pointers to static data, which may be overwritten by later calls. Copying the struct hostent does not suffice, since it contains pointers; a deep copy is required.

KennyTM
Why "global" ? Global and static are not the same thing.
Ben
A: 

hm, but why do I get ==28514== 11 bytes in 1 blocks are definitely lost in loss record 15 of 581

==28514== at 0x4024C4C: malloc (vg_replace_malloc.c:195)

==28514== by 0x454775F: strdup (strdup.c:43)

==28514== by 0x6126FFD: ???

==28514== by 0x45BA0B3: gethostbyaddr_r@@GLIBC_2.1.2 (getXXbyYY_r.c:253)

==28514== by 0x45B9E9B: gethostbyaddr (getXXbyYY.c:116)

==28514== by 0x807F94A: locate_host (locate_host.c:93)

==28514== by 0x8066336: begin_session (citserver.c:925)

==28514== by 0x8068A2B: worker_thread (sysdep.c:1204)

==28514== by 0x80866D9: ctdl_internal_thread_func (threads.c:849)

==28514== by 0x4215584: start_thread (pthread_create.c:300)

==28514== by 0x45A329D: clone (clone.S:130)

then? (its citadel.org citserver with one session being opened)

dothebart
This should be posted as its own question, not as an answer to an old question.
Andrew Medico
@Andrew: I think he was testing my code. However, I think a hostent is more than 11 bytes. You might have other errors in the code you're testing
piggles
no, I was testing existing code, And was looking for some advice how to handle this. but, as my stack frame shows, it seems as if its using a _r function as backend, right?probably the best solution would be to use that one in first place?
dothebart