views:

380

answers:

7

I have a question regarding memory allocation order. In the following code I allocate in a loop 4 strings. But when I print the addresses they don't seem to be allocated one after the other... Am I doing something wrong or is it some sort of defense mechanism implemented by the OS to prevent possible buffer overflows? (I use Windows Vista).

Thank you.

 char **stringArr;
 int size=4, i;

 stringArr=(char**)malloc(size*sizeof(char*));
 for (i=0; i<size; i++)
    stringArr[i]=(char*)malloc(10*sizeof(char));

 strcpy(stringArr[0], "abcdefgh");
 strcpy(stringArr[1], "good-luck");
 strcpy(stringArr[2], "mully");
 strcpy(stringArr[3], "stam");

 for (i=0; i<size; i++) {
  printf("%s\n", stringArr[i]);
  printf("%d  %u\n\n", &(stringArr[i]), stringArr[i]);
 }

Output:

abcdefgh 9650064 9650128

good-luck 9650068 9638624

mully 9650072 9638680

stam 9650076 9638736

+3  A: 

But when I print the addresses they don't seem to be allocated one after the other...

So?

Am I doing something wrong or is it some sort of defense mechanism implemented by the OS to prevent possible buffer overflows?

Probably "neither".

Just out of interest, what addresses do you get?

Anon.
So? Well, in older Operating Systems the allocation was block after block. You can even read about this in tutorials on buffer overflows from ten years ago.For an example: I just edited the post and added an example.
thedp
Exactly where newly-allocated memory is in your address space is not defined. Prior behaviour has little-to-no bearing on how it behaves now.
Anon.
http://en.wikipedia.org/wiki/Address_space_layout_randomizationSearch for "Windows" in the article.
thedp
+4  A: 

You shouldn't depend on any particular ordering or spacing of values returned by malloc. It behaves in mysterious and unpredictable ways.

Keith Randall
You're right. To tell you the truth this all started from a homework assignment. A friend of mine had some difficult time with a program he wrote. After hours of debugging he came to me, so then I wasted more time debugging it. Until I finally printed the the allocated address. The exercise forces you to allocate an array of strings and search them by moving through the memory. The thing is, it not mandatory and it's quite old... :)
thedp
I'm 100% sure malloc did allocate memory by order... Well, the last time I tried that was like 10 years ago :) You can even read about it in old buffer overflow related tutorials.
thedp
If someone's giving homework assignments that depend on undefined behaviour, that person probably shouldn't be teaching programming.
Anon.
`malloc` behavior is undefined. A secure implementation will allocate memory at random positions so that *successful* buffer overflows become very unlikely. A fast implementation will just allocate the next section of free address space.
jbcreix
+7  A: 

Typically when you request memory through malloc(), the C runtime library will round the size of your request up to some minimum allocation size. This makes sure that:

  • the runtime library has room for its bookkeeping information
  • it's more efficient for the runtime library to manage allocated blocks that are all multiples of some size (such as 16 bytes)

However, these are implementation details and you can't really rely on any particular behaviour of malloc().

Greg Hewgill
+4  A: 

Typically it is reasonable to expect that a series of chronological allocations will result in a memory addresses that are somehow related, but as others have pointed out, it is certainly not a requirement of the heap manager. In this particular case, though, it is possible that you are seeing results of the low fragmentation heap. Windows keeps lists of small chunks of memory that can quickly satisfy a request. These could be in any order.

Mark Wilkins
+2  A: 

You can't depend on malloc to give you contiguous addresses. It's entirely up to the implementation and presumably the current state of the heap; some implementations may, many won't.

If you need the addresses to be contiguous, allocate one large block of memory and set up your pointers to point to different areas within it.

Dan Olson
+2  A: 

As others have mentioned, there is no standard to specify in which order the memory blocks allocated by malloc() should be located in the memory. For example, freed blocks can be scattered all around the heap and they may be re-used in any order.

But even if the blocks happen to be one after each other, they most likely do not form a contiguous block. In order to reduce fragmentation, the heap manager only allocates blocks of specific size, for example power of two (64, 128, 256, 512 etc. bytes). So, if you reserve 10 bytes for a string, there may be perhaps 22 or 54 un-used bytes after that.

The memory overhead is another reason why it is not good idea to use dynamic memory allocation unless really necessary. It is much easier and safer just to use a static array.

PauliL
+1  A: 

Since you are interesting in knowing the addresses returned by malloc(), you should make sure you are printing them properly. By "properly", I mean that you should use the right format specifier for printf() to print addresses. Why are you using "%u" for one and "%d" for another?

You should use "%p" for printing pointers. This is also one of the rare cases where you need a cast in C: because printf() is a variadic function, the compiler can't tell that the pointers you're passing as an argument to it need to be of the type void * or not.

Also, you shouldn't cast the return value of malloc().

Having fixed the above, the program is:

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

int main(void)
{
    char **stringArr;
    int size=4, i;

    stringArr = malloc(size * sizeof *stringArr);

    for (i=0; i < size; i++)
        stringArr[i] = malloc(10 * sizeof *stringArr[i]);

    strcpy(stringArr[0], "abcdefgh");
    strcpy(stringArr[1], "good-luck");
    strcpy(stringArr[2], "mully");
    strcpy(stringArr[3], "stam");

    for (i=0; i<size; i++) {
        printf("%s\n", stringArr[i]);
        printf("%p %p\n", (void *)(&stringArr[i]), (void *)(stringArr[i]));
    }
    return 0;
}

and I get the following output when I run it:

abcdefgh
0x100100080 0x1001000a0
good-luck
0x100100088 0x1001000b0
mully
0x100100090 0x1001000c0
stam
0x100100098 0x1001000d0

On my computer, char ** pointers are 8 bytes long, so &stringArr[i+1] is at 8 bytes greater than &stringArr[i]. This is guaranteed by the standard: If you malloc() some space, that space is contiguous. You allocated space for 4 pointers, and the addresses of those four pointers are next to each other. You can see that more clearly by doing:

printf("%d\n", (int)(&stringArr[1] - &stringArr[0]));

This should print 1.

About the subsequent malloc()s, since each stringArr[i] is obtained from a separate malloc(), the implementation is free to assign any suitable addresses to them. On my implementation, with that particular run, the addresses are all 0x10 bytes apart.

For your implementation, it seems like char ** pointers are 4 bytes long.

About your individual string's addresses, it does look like malloc() is doing some sort of randomization (which it is allowed to do).

Alok