11

programming language: C platform: ARM Compiler: ADS 1.2

I need to keep track of simple melloc/free calls in my project. I just need to get very basic idea of how much heap memory is required when the program has allocated all its resources. Therefore, I have provided a wrapper for the malloc/free calls. In these wrappers I need to increment a current memory count when malloc is called and decrement it when free is called. The malloc case is straight forward as I have the size to allocate from the caller. I am wondering how to deal with the free case as I need to store the pointer/size mapping somewhere. This being C, I do not have a standard map to implement this easily.

I am trying to avoid linking in any libraries so would prefer *.c/h implementation.

So I am wondering if there already is a simple implementation one may lead me to. If not, this is motivation to go ahead and implement one.

EDIT: Purely for debugging and this code is not shipped with the product.

EDIT: Initial implementation based on answer from Makis. I would appreciate feedback on this.

EDIT: Reworked implementation

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <limits.h>

static size_t gnCurrentMemory = 0;
static size_t gnPeakMemory    = 0;

void *MemAlloc (size_t nSize)
{
  void *pMem = malloc(sizeof(size_t) + nSize);

  if (pMem)
  {
    size_t *pSize = (size_t *)pMem;

    memcpy(pSize, &nSize, sizeof(nSize));

    gnCurrentMemory += nSize;

    if (gnCurrentMemory > gnPeakMemory)
    {
      gnPeakMemory = gnCurrentMemory;
    }

    printf("PMemAlloc (%#X) - Size (%d), Current (%d), Peak (%d)\n",
           pSize + 1, nSize, gnCurrentMemory, gnPeakMemory);

    return(pSize + 1);
  }

  return NULL;
}

void  MemFree (void *pMem)
{
  if(pMem)
  {
    size_t *pSize = (size_t *)pMem;

    // Get the size
    --pSize;

    assert(gnCurrentMemory >= *pSize);

    printf("PMemFree (%#X) - Size (%d), Current (%d), Peak (%d)\n",
           pMem,  *pSize, gnCurrentMemory, gnPeakMemory);

    gnCurrentMemory -= *pSize;

    free(pSize);
  }
}

#define BUFFERSIZE (1024*1024)

typedef struct
{
  bool flag;
  int buffer[BUFFERSIZE];
  bool bools[BUFFERSIZE];
} sample_buffer;

typedef struct
{
  unsigned int whichbuffer;
  char ch;
} buffer_info;


int main(void)
{
  unsigned int i;
  buffer_info *bufferinfo;

  sample_buffer  *mybuffer;

  char *pCh;

  printf("Tesint MemAlloc - MemFree\n");

  mybuffer = (sample_buffer *) MemAlloc(sizeof(sample_buffer));

  if (mybuffer == NULL)
  {
    printf("ERROR ALLOCATING mybuffer\n");

    return EXIT_FAILURE;
  }

  bufferinfo = (buffer_info *) MemAlloc(sizeof(buffer_info));

  if (bufferinfo == NULL)
  {
    printf("ERROR ALLOCATING bufferinfo\n");

    MemFree(mybuffer);

    return EXIT_FAILURE;
  }

  pCh = (char *)MemAlloc(sizeof(char));

  printf("finished malloc\n");

  // fill allocated memory with integers and read back some values
  for(i = 0; i < BUFFERSIZE; ++i)
  {
    mybuffer->buffer[i] = i;
    mybuffer->bools[i] = true;
    bufferinfo->whichbuffer = (unsigned int)(i/100);
  }


  MemFree(bufferinfo);
  MemFree(mybuffer);

  if(pCh)
  {
    MemFree(pCh);
  }

  return EXIT_SUCCESS;
}
dubnde
  • 4,359
  • 9
  • 43
  • 63
  • I don't think you need two malloc()'s in MemAlloc. Just write a macro to determine a good size for alignment (or use 64 bits, I think it would be sufficient for every case) and add nSize by that amount before allocating the memory. – Makis May 12 '09 at 13:15
  • Thanks Makis. I am on 32bit platform. I have updated my implementation to use single malloc in MemAlloc. I do not understand the point on alignment though. If it is not asking too much, are you able to point out in my implementation where this could be an issue. Presumably, if the pointer passed to MemFree or returned from malloc is already not aligned, there is not much that can be done as these would be unaligned anyway if I did not use my wrapper, right? – dubnde May 12 '09 at 16:31
  • 1
    Here's a nice explanation on the issue: http://www.goingware.com/tips/getting-started/alignment.html I would have the size info in 32 bits as well, this should clear the issue. The problem can be like this: You reserve memory starting from location X and the first two bytes is your size info, so you return x+2 to the caller. If, however, alignment is 4 bytes, you could run into a problem. So check what size size_t is, or if you want portable code, you need to define some macros. – Makis May 13 '09 at 06:03
  • ok. thanks. sizeof(size_t) is 4 bytes. I am actually going to use uint32_t to make it more explicit – dubnde May 13 '09 at 08:25

7 Answers7

13

You could allocate a few extra bytes in your wrapper and put either an id (if you want to be able to couple malloc() and free()) or just the size there. Just malloc() that much more memory, store the information at the beginning of your memory block and and move the pointer you return that many bytes forward.

This can, btw, also easily be used for fence pointers/finger-prints and such.

Makis
  • 12,468
  • 10
  • 62
  • 71
  • 3
    Make sure that the pointer you return has the same alignment or better than the pointer that malloc returns, just in case. – Eyal May 12 '09 at 12:05
  • Good point, Eyal. No matter how many times I get burnt with misalignment (usually with structs) I still tend to forget it :) – Makis May 12 '09 at 12:42
  • 1
    The size is probably already there, cast the returned pointer to (int *) and check the value at ptr[-1] or ptr[-2]. Note that the allocated size may be rounded up to maintain alignment, so a request for a 123-byte buffer may return 128 bytes, so check accordingly. – TMN May 12 '09 at 17:44
2

Either you can have access to internal tables used by malloc/free (see this question: Where Do malloc() / free() Store Allocated Sizes and Addresses? for some hints), or you have to manage your own tables in your wrappers.

Community
  • 1
  • 1
mouviciel
  • 66,855
  • 13
  • 106
  • 140
1

You could always use valgrind instead of rolling your own implementation. If you don't care about the amount of memory you allocate you could use an even simpler implementation: (I did this really quickly so there could be errors and I realize that it is not the most efficient implementation. The pAllocedStorage should be given an initial size and increase by some factor for a resize etc. but you get the idea.)

EDIT: I missed that this was for ARM, to my knowledge valgrind is not available on ARM so that might not be an option.

static size_t indexAllocedStorage = 0;
static size_t *pAllocedStorage = NULL;
static unsigned int free_calls = 0; 
static unsigned long long int total_mem_alloced = 0; 

void * 
my_malloc(size_t size){
    size_t *temp;
    void *p = malloc(size);
    if(p == NULL){
    fprintf(stderr,"my_malloc malloc failed, %s", strerror(errno));
    exit(EXIT_FAILURE);
    }

    total_mem_alloced += size;

    temp = (size_t *)realloc(pAllocedStorage, (indexAllocedStorage+1) * sizeof(size_t));
    if(temp == NULL){
        fprintf(stderr,"my_malloc realloc failed, %s", strerror(errno));
         exit(EXIT_FAILURE);
    }

    pAllocedStorage = temp; 
    pAllocedStorage[indexAllocedStorage++] = (size_t)p;

    return p;
}

void 
my_free(void *p){
    size_t i;
    int found = 0;

    for(i = 0; i < indexAllocedStorage; i++){
    if(pAllocedStorage[i] == (size_t)p){
        pAllocedStorage[i] = (size_t)NULL;
        found = 1;
        break;
        }
    }

    if(!found){
        printf("Free Called on unknown\n");
    }

    free_calls++;
    free(p);
}

void 
free_check(void) {
    size_t i;

    printf("checking freed memeory\n");
    for(i = 0; i < indexAllocedStorage; i++){   
        if(pAllocedStorage[i] != (size_t)NULL){
            printf( "Memory leak %X\n", (unsigned int)pAllocedStorage[i]);
            free((void *)pAllocedStorage[i]);
        }
    }

    free(pAllocedStorage);
    pAllocedStorage = NULL;
}
Sweeney
  • 672
  • 4
  • 6
0

I've been trying out some of the same techniques mentioned on this page and wound up here from a google search. I know this question is old, but wanted to add for the record...

1) Does your operating system not provide any tools to see how much heap memory is in use in a running process? I see you're talking about ARM, so this may well be the case. In most full-featured OSes, this is just a matter of using a cmd-line tool to see the heap size.

2) If available in your libc, sbrk(0) on most platforms will tell you the end address of your data segment. If you have it, all you need to do is store that address at the start of your program (say, startBrk=sbrk(0)), then at any time your allocated size is sbrk(0) - startBrk.

3) If shared objects can be used, you're dynamically linking to your libc, and your OS's runtime loader has something like an LD_PRELOAD environment variable, you might find it more useful to build your own shared object that defines the actual libc functions with the same symbols (malloc(), not MemAlloc()), then have the loader load your lib first and "interpose" the libc functions. You can further obtain the addresses of the actual libc functions with dlsym() and the RTLD_NEXT flag so you can do what you are doing above without having to recompile all your code to use your malloc/free wrappers. It is then just a runtime decision when you start your program (or any program that fits the description in the first sentence) where you set an environment variable like LD_PRELOAD=mymemdebug.so and then run it. (google for shared object interposition.. it's a great technique and one used by many debuggers/profilers)

cptstubing06
  • 322
  • 1
  • 4
  • It is a very simple in house OS. 1) No (2) sbrk not available (3)shared objects not available. – dubnde Aug 07 '13 at 11:06
0

I would use rmalloc. It is a simple library (actually it is only two files) to debug memory usage, but it also has support for statistics. Since you already wrapper functions it should be very easy to use rmalloc for it. Keep in mind that you also need to replace strdup, etc.

quinmars
  • 11,175
  • 8
  • 32
  • 41
0

Your program may also need to intercept realloc(), calloc(), getcwd() (as it may allocate memory when buffer is NULL in some implementations) and maybe strdup() or a similar function, if it is supported by your compiler

dmityugov
  • 4,390
  • 23
  • 18
  • 1
    If you override malloc() (and realloc(), calloc(), alloca() and free()), then you get the others for free (so to speak), as they all just call malloc() internally. – TMN May 12 '09 at 17:49
  • my program only uses MemAlloc and MemFree so it is sufficient for this purpose to only intercept malloc and free. – dubnde May 13 '09 at 15:42
0

If you are running on x86 you could just run your binary under valgrind and it would gather all this information for you, using the standard implementation of malloc and free. Simple.

Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533