Question

Q1

In some open source libraries, there is a common pattern to hold a private buffer:

/* ======== in modnamemapping.c ======== */
static char *private_buffer = NULL;
const char *getname( int id ) {
  if ( !private_buffer )
    private_buffer = (char *) malloc( 0x100 ); // in addition, the length may not
                                               // a compile-period-constant, or
                                               // here is some realloc() and the
                                               // branch does not enter only once.
  snprintf( private_buffer, 0x100, "NameOf%d", id );
  return private_buffer;
}
// *NO* code to free private_buffer ...

As I know, this should result a memory leak, is it ?

I know only one method to fix up this issue, to use pthread_key and pthread_once. But there are some embeded environments that do not have builtin implements of them, and this method looks trivial and not pretty for a non-threaded program. Is there other simple and clean choice to handle this ?

Q2

There is similar behavior in libc. I wrote a simple test code of libc function strftime(), which makes valgrind report some definitely lost on my OS X Mavericks. (compiler apple-gcc42 ver 4.2.1-5666.3 in brew)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main( void ) {
    char buf[0x40], *fmt = "%x %X";
    time_t t1 = time( NULL );
    struct tm t2;
    int ret;
    (void) localtime_r( &t1, &t2 );
    ret = strftime( buf, sizeof(buf), fmt, &t2 );
    printf( "strftime('%s', <now>) = %d: [%s]\n", fmt, ret, buf );
    return 0;
}

one of the definitely lost:

==46746== 2,242 (16 direct, 2,226 indirect) bytes in 1 blocks are definitely lost in loss record 83 of 87
==46746==    at 0x70AB: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==46746==    by 0x334FE6: _nc_table_new (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x334A63: __token_table_add_block_invoke (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0xB62AC: _dispatch_client_callout (in /usr/lib/system/libdispatch.dylib)
==46746==    by 0xB621B: dispatch_once_f (in /usr/lib/system/libdispatch.dylib)
==46746==    by 0x3328A6: token_table_add (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x3326B2: notify_register_check (in /usr/lib/system/libsystem_notify.dylib)
==46746==    by 0x196AB5: notify_register_tz (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x1965EA: tzsetwall_basic (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x1967A7: _st_tzset_basic (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x198FAE: strftime_l (in /usr/lib/system/libsystem_c.dylib)
==46746==    by 0x100000EB2: main (strftime.c:10)

and summary:

==46746== LEAK SUMMARY:
==46746==    definitely lost: 32 bytes in 2 blocks
==46746==    indirectly lost: 4,298 bytes in 7 blocks
==46746==      possibly lost: 10,808 bytes in 1 blocks
==46746==    still reachable: 16,384 bytes in 1 blocks
==46746==         suppressed: 25,272 bytes in 375 blocks

Is there a cleanup-strftime function in libc should be called before program quit ? Or a new patch of libc about it ?

Was it helpful?

Solution

In the first case, you are correct that the memory is leaked when the program exits, but it is a one-time allocation of a small (256-byte) chunk of memory. It should only be 'possibly lost' since there is still a pointer to the allocated space. If that's the worst leak you've got, you're doing OK and you could write a suppression for it.

With the second scenario, your code nominally calls strftime(), but the runtime says strftime_l() is called instead, presumably with a null as the locale pointer. It is less clear that this is harmless; why are there two direct and two indirect blocks lost? It might be worth calling strftime() a few times in a loop to see what the magnitude of the problem is. If it stays the same, then it probably isn't worth worrying about. If the amount leaked goes up, then you probably have found a bug. Maybe 10.9.1 will fix that (must reboot!). There isn't a cleanup_strftime() function; there shouldn't be a need for one.

The possibly lost is a nuisance too. I'd check that out. You may be able to create suppressions for the memory, so your code will appear to run cleanly (as cleanly as the run-time system allows). But it isn't desirable.

OTHER TIPS

Q1 is a memory leak of sorts. There's always:

static char private_buffer[0x100];

and remove the allocation code. This will work for some environments, but not all (e.g. ROPI code). The real fix in this case is to fix the definition of getname:

const char *getname( int id, char* buf, size_t len ) {
  if (buf)
     snprintf( buf, len, "NameOf%d", id );
  return buf;
}

But that means fixing up all of getname's callers as well, which probably doesn't qualify as simple and clean.

WIth Q2 there's no cleanup function for strftime. It might be worth investigating as Jonathan Leffler suggested. Underlying library functions "leak" quite often, but usually aren't a problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top