4

I've been writing an implementation of malloc and was wondering if someone could help me with this problem.

Basically, I would like to reuse memory after allocating it using sbrk(), and having made certain that the memory is free.

So essentially, imagine my memory is like this

|------------------------------|

...and I do some allocations. When I allocate memory, each bit has a head (h) and data (d).

|hddddddhddd---hdd--hddd-------|

Now I've got these holes, and if I want to use say, the first gap in my diagram, how do I set it up so that it's got a head (h) and a body (dd) also?

I've gotten to the point where now I've got a pointer to the memory location I want. In C, its pointed to by a pointer. The pointer has a custom type, where "meta" is a struct I defined. So now I have

metaStruct * mypointer = the memory address.

But when I try to do

mypointer->size = 30;

Or

mypointer->buddy = 1;

I get a segfault.

The question: how do I set it up so that the memory address, which has been allocated via sbrk(), will have the form of my struct? Obviously I can't just go myPointer = malloc(sizeof(metaStruct)), because I am writing malloc itself. I'm also not interested in sbrk()'ing more space, but rather, utilizing the existing space that I'm pointing to (I want to disregard its junk data and use the space).

How do I go about doing that?

Navin Aggrawal
  • 189
  • 1
  • 3
  • 12
  • Incidentally, many newer `malloc(3)` implementations call `mmap(2)` with `MAP_ANONYMOUS`, to allocate new zeroed pages for a process. Because the allocations can be done as small as page-sizes, and can be released back to the OS in any order, it is easier to return memory to the OS from a process. And might be easier to allocate new pages for storage of your own internal datastructures. – sarnold Mar 26 '11 at 10:31
  • Thanks sarnold -- I'm aware of mmap but I'm doing this for learning purposes. With my sbrk() implementation I was only wondering if I needed to explicitly set something up to use the memory that the pointer referred to? Like, memset or something. I just want to solve this segfault, haha. I've already gotten so far it doesn't make sense to start over :D – Navin Aggrawal Mar 26 '11 at 10:41
  • I can't argue against that! :) Happy hacking. – sarnold Mar 26 '11 at 10:49
  • thanks sarnold. now I wonder who knows how to solve this... – Navin Aggrawal Mar 26 '11 at 10:56

1 Answers1

4

As far as I know, p=sbrk(n) enlarges the available address space of (at least) n bytes and returns the base address of the new allocated area in "p". So you now have a block of memory starting at "p" and n bytes long (probably more than n, it depends on the system).

So I suppose that your "metaStruct" contains a "size" field, a "next free area" field, and a "data" field,

metaStruct * m ;
p=sbrk(sizeof(metaStruct)+ data_size);
m = (metaStruct *)p;
m->size = data_size;
m->next = NULL;
memcpy(m->data, ...,data_size);

The code is not perfect, on some systems the sbrk function (indeed it's often a function, not a basic system call - and of course you should check if sbrk fails) doesn't return aligned pointers, so you have to align the pointer manually. Also, you can obtain the actual allocated size by calling sbrk(0) after sbrk(n) and calculating the difference between the two pointers. In general, you should mainatin a collection of "free blocks" and try to use them fist, then call sbrk only if none of them is large enough.

Giuseppe Guerrini
  • 4,274
  • 17
  • 32
  • Thanks Giuseppe -- so I already did everything you said above. My issue is with my collection of free blocks: when I have a free block, I sometimes want to split it into 2 smaller blocks. I do that by simply altering my metaStruct to say "size = size / 2" or something along those lines. Then I get a pointer to the second half of my memory -- here is where my problem comes in. I cast the pointer like you do, but when I do m->size, it segfaults. Any ideas as to why? Thanks again for your help :)) – Navin Aggrawal Mar 26 '11 at 10:55
  • @Navin: why do you want to split it in half? Allocators normally only split chunks on malloc(), returning to the user one chunk the size he asked for, and leaving the rest as a new chunk on the free list. – ninjalj Mar 26 '11 at 11:23
  • @ninjalj: I think OP is implementing a buddy system allocator, widely acknowledged as the *worst* type... – R.. GitHub STOP HELPING ICE Mar 26 '11 at 12:20
  • @Navin: there are many things that can go wrong when you spit a free block. At least you should check if the remainig part is big enough to contain the header plus a minimal amount of data. Also, on most system the pointer alignement is important, so you must assure that the second part starts (at least!) at a multiple of the physical CPU word (and it could be not enough). Depending on the system, using a pointer not aligned may cause exceptions, unexpected behaviours or loss of performance. – Giuseppe Guerrini Mar 26 '11 at 13:17
  • @Navin(contiued): a typical pattern to split a ploc in a safe way is: round the size you need up to the system word size;if block->size-required_zie > sizeof(metaStruct) you can split; else give up. To split the block a possible way is newblock=(metaStruct*)(((char *)block) + sizeof(metaStruct)+rounded_size). – Giuseppe Guerrini Mar 26 '11 at 13:29
  • Hi thanks Guiseppe, so yeah I am splitting the free block because when I malloc, if I find a block that's drastically larger than what I need, I want to be able to only use a part of it and put the rest on my "free" list. How do I know the system word size? I think your advice is probably gonna give me my solution but I am not entirely sure where to proceed from here. From what I understand, my pointer is not aligned and that might be causing my issues? – Navin Aggrawal Mar 27 '11 at 18:09
  • Hi Navin. Mine is just a hypothesys, a misaligned pointer MAY cause problems (e.g. on ARM). The correct alignment depends essentially on the CPU you are using, so it's a matter of studying the processor's architecure. The compiler may add some rules, so you should also have a look to the way the compiler align things. Here is an article that may be halpful for you: http://stackoverflow.com/questions/2505912/c-64-bit-pointer-alignment . Bye! – Giuseppe Guerrini Mar 27 '11 at 18:51
  • Thanks Giuseppe. I removed the code that does the splitting and as we suspected, my segfaults disappeared! So basically i need to learn how to split free blocks correctly / with aligned pointers. Any tips on how to do that would be appreciated – Navin Aggrawal Mar 28 '11 at 04:25
  • Let's assume that the required alignment for your system is "a", "b" is the pointer to the block to slpit, and "s" the required size. The size may be rounded this way: s=s+a-((s-1)%a)+1. The pointer "p" to the free part of the block is p=(metaStruct*)(((char *)(&b[1]))+s). I hope that these simple notes may help you. Bye! – Giuseppe Guerrini Mar 28 '11 at 22:03