0

I'm writing a short program where I need to first malloc an array of structure, and if asked by user to malloc others, the allocation give them consequentially addresses (i've prooved this), BUT when i realloc() one of them the reallocation invades the space of the others making them unusable...

How can I do to avoid this problem???

  • 1
    Use the library and the language without invoking or relying on **undefined behavior**? You can't rely on consecutive `malloc()` to return consecutive addresses. Your observation doesn't mean that behavior is defined. You can observe defined behavior (obviously), but that doesn't mean all behavior you observe is defined. – WhozCraig Jan 28 '14 at 21:37
  • 2
    Welcome to SO. Please take your time and look around how and what questions are typically asked here. Yours, is quite vague and almost incomprehensible. – Jens Gustedt Jan 28 '14 at 21:38
  • What is UB? Sorry I'm new to this language I'm starting right now to learn it... – user3246416 Jan 28 '14 at 21:39
  • 3
    You are (un)lucky that `malloc()` was giving you sequential addresses. You should never assume anything about what `malloc()` will return relative to other allocations. The `realloc()` will never return you a pointer that overlaps with data that is still allocated; if you think it did, you are confused (or you have confused `malloc()` et al by double releasing or some other form of memory abuse). – Jonathan Leffler Jan 28 '14 at 21:39
  • Sure I'm confused I'm not a professional user... I've tried to printf the addresses given to the allocated and re-allocated arrays and they overlap, so I though that was the problem. – user3246416 Jan 28 '14 at 21:42
  • 2
    How big is the code that you are working with. If it is 50 lines or less, post it. If it's bigger, see [How to create a Minimal, Complete, Tested and Readable Example](http://stackoverflow.com/help/mcve) and reduce your code to be an MCTRE (MCVE, [SSCCE](http://sscce.org/) — alternative acronyms for the same basic idea). – Jonathan Leffler Jan 28 '14 at 21:49
  • @user3246416 What you say will not happen if you did things properly. That means the problem is that you have a bug in your code. – nos Jan 28 '14 at 21:53
  • 1
    UB is short for 'undefined behaviour'. ISO/IEC 9899:2011 §3.4.3 **undefined behavior** _behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements. NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message)._ – Jonathan Leffler Jan 28 '14 at 22:48

1 Answers1

1

What you're doing is touching on Undefined Behavior, and is Ill Advised at the very least. If you need fine-grained control over memory blocks like this, you need to ask the system's memory allocator to give you a large block to manage yourself.

The system allocator is shared between your threads and any system or other allocating calls you make - such as strdup. The reordering that happens with realloc is caused by the fact that realloc must first allocate a new block and then copy the old data into it before making the older block available. But this same problem is going to occur elsewhere in your application's lifetime.

There are also many memory-allocator strategies. Some memory allocators will actually allocate a slightly larger block than you request and use the extra space to provide information about the allocation. E.g. when you ask for 16 bytes of memory, they allocate 16 + sizeof(size_t) and store the size of the allocation infront of the address they return to you:

void* malloc(size_t bytes)
{
    uint32_t* block = _internal_malloc(bytes + sizeof uint32_t);
    *block = bytes;
    return &block[1]; // return a pointer to after the size we stored.
}

Memory allocators also tend to change between versions of operating systems, so relying on their behavior is a pretty bad idea.

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

int main() {
    char* a = malloc(32);
    char* b = malloc(32);
    char* s = strdup("hello");
    char* c = malloc(32);

    printf("a = %p, b = %p (a + 32 = %p), c = %p (b + 32 = %p)\n", a, b, a+32, c, b + 32);

    // your code goes here
    return 0;
}

Output:

a = 0x83af008, b = 0x83af030 (a + 32 = 0x83af028), c = 0x83af068 (b + 32 = 0x83af050)

You can see that these blocks are in order but not contiguous, there's also an extended gap between b and c because of the strdup.

Another issue that can affect ordering is fragmentation of the free pool.

http://ideone.com/cbAfzm

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

int main() {
    char* a = malloc(32);
    char* b = malloc(32);
    char* s = strdup("hello");
    free(s);
    char* c = malloc(32);

    printf("a = %p, b = %p (a + 32 = %p), c = %p (b + 32 = %p)\n", a, b, a+32, c, b + 32);

    // your code goes here
    return 0;
}

Here, even though we freed s, we've fragmented the allocation causing a split and we're only going to get that address back when we ask for an equal or smaller allocation.

kfsone
  • 23,617
  • 2
  • 42
  • 74