Question

As far as I can tell, asprintf calls malloc. If I replace malloc with the Boehm GC, a call to asprintf still calls the traditional malloc - at least that's what valgrind is telling me:

Here's the malloc macro:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#include <gc.h>
#define malloc(n)    GC_MALLOC(n)
#define calloc(m,n)  GC_MALLOC((m)*(n))
#define realloc(p,n) GC_REALLOC((p),(n))

typedef char * string;

And here is the valgrind report:

hopcroft:didactic_scheme(flexible_strings) scotttaylor$ valgrind --suppressions=./boehm-gc.suppressions --leak-check=full bin/escheme -e 1
==16130== Memcheck, a memory error detector
==16130== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==16130== Using Valgrind-3.6.0.SVN and LibVEX; rerun with -h for copyright info
==16130== Command: bin/escheme -e 1
==16130== 
--16130-- bin/escheme:
--16130-- dSYM directory is missing; consider using --dsymutil=yes
1==16130== 
==16130== HEAP SUMMARY:
==16130==     in use at exit: 4,312 bytes in 3 blocks
==16130==   total heap usage: 3 allocs, 0 frees, 4,312 bytes allocated
==16130== 
==16130== 128 bytes in 1 blocks are definitely lost in loss record 2 of 3
==16130==    at 0x100012D75: malloc (vg_replace_malloc.c:236)
==16130==    by 0x1000918EC: asprintf (in /usr/lib/libSystem.B.dylib)
==16130==    by 0x1000013FA: printInt (in bin/escheme)
==16130==    by 0x100001D38: print (in bin/escheme)
==16130==    by 0x100001DC5: main (in bin/escheme)
==16130== 
==16130== LEAK SUMMARY:
==16130==    definitely lost: 128 bytes in 1 blocks
==16130==    indirectly lost: 0 bytes in 0 blocks
==16130==      possibly lost: 0 bytes in 0 blocks
==16130==    still reachable: 4,184 bytes in 2 blocks
==16130==         suppressed: 0 bytes in 0 blocks
==16130== Reachable blocks (those to which a pointer was found) are not shown.
==16130== To see them, rerun with: --leak-check=full --show-reachable=yes
==16130== 
==16130== For counts of detected and suppressed errors, rerun with: -v
==16130== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 66 from 13)

Here's the code in which the malloc call is coming from:

static string printInt(Object self) {
  string str;
  asprintf(&str, "%lu", getValueInt(self));
  return str;
}

A workaround might be to use asprintf, then use malloc to copy it so that the malloc macro is used instead of the primitive function:

static string printInt(Object self) {
  string tmp;
  string str;

  asprintf(&tmp, "%lu", getValueInt(self));
  str = calloc(sizeof(string), strlen(tmp) + 1);

  strcpy(str, tmp);
  free(tmp);

  return str;
}

That seems silly - it involves a bunch of unnecessary copying and also happens to be a code eye sore IHMO. So is there a safe way to use asprintf and other system libraries that might call the native malloc while still using the Boehm GC? Is there an alternative to asprintf that I should be using instead?

Was it helpful?

Solution

snprintf returns the number of characters that would have been written had the provided buffer been large enough. You could call this method twice (once to get the right buffer size and then again with a buffer large enough to obtain the output), however this is probably going to be less efficient than just copying the output of asprintf into a collectable buffer. Here's an example containing code that allocates a buffer large enough to contain the maximum value of an unsigned long for 32-bit systems. On systems where there is not enough space, the buffer is reallocated and reformatted.

#include <limits.h>

...

unsigned long intValue = getValueInt(self);
size_t maxLength = 11; // heuristic
char *buf = malloc(maxLength);

int result = snprintf(buf, maxLength, "%lu", intValue);
if (result > maxLength)
{
    // shouldn't ever get here, but just in case the buffer is too small
    // we reallocate it to the correct size and try again.
    buf = malloc(result);
    snprintf(buf, result, "%lu", intValue);
}

return buf;

OTHER TIPS

According to this page, you can compile libgc (the boehm-gc library) with

-DREDIRECT_MALLOC=GC_malloc -DIGNORE_FREE

which ought to intercept the call to malloc in asprintf. NB: haven't tried this.

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