20

The realloc reference says:

The function may move the memory block to a new location, in which case the new location is returned.

Does it mean that if I do this:

void foo() {

        void* ptr = malloc( 1024 );

        unsigned char* cptr = ( unsigned char* )ptr+256;

        ptr = realloc( ptr, 4096 );
}

then cptr may become invalid if realloc moves the block?

If yes, then does realloc signal in any way, that it will move the block, so that I can do something to prevent cptr from becoming invalid?

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
zajcev
  • 303
  • 2
  • 7
  • This is a good question +1 from me as it emphasize the fundamental learning curve involving realloc... – t0mm13b Jan 31 '10 at 15:45

5 Answers5

9

Yes, cptr will become invalid as realloc moves the block! And no, there is no mention of signalling to you to tell that it is moving the block of memory. By the way, your code looks iffy...read on... please see my answer to another question and read the code very carefully on how it uses realloc. The general consensus is if you do this:

void *ptr = malloc(1024);

/* later on in the code */

ptr = realloc(ptr, 4096);

/* BAM! if realloc failed, your precious memory is stuffed! */

The way to get around that is to use a temporary pointer and use that as shown:

void *ptr = malloc(1024);

/* later on in the code */

void *tmp = realloc(ptr, 4096);

if (tmp != null) ptr = tmp;

Edit: Thanks Secure for pointing out a gremlin that crept in when I was typing this earlier on.

Community
  • 1
  • 1
t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • It's not real code - it's just something to show what I was going to do. So is there any way to resize an existing block of memory without moving it ( or tell the program that it's not possible? ). If I call realloc and it succeeds by moving the block, then is it possible to somehow keep the old addresses valid, so that I can "undo" the realloc? – zajcev Jan 31 '10 at 15:39
  • No! You cannot do that...that is compiler/linker/runtime dependent. And no you cannot keep the old addresses as the heap will get fragmented over the course and lifetime of the program. In short, you cannot absolutely pin down the old addresses as the very essence of pointers is based on dynamic addressing...and no you cannot undo the realloc... – t0mm13b Jan 31 '10 at 15:43
  • This is the most useless cast of the return value of malloc I've ever seen. And why do you cast the return of malloc, but not the return of realloc? – Secure Jan 31 '10 at 17:35
  • @Secure: sorry about that - that's old skool C programming....and firmly engrained into my brain...ever worked with C 89 standard in early 90's, then you would know what I'm talking about! :) – t0mm13b Jan 31 '10 at 17:51
  • @Secure: the old malloc returned void * hence the cast, I merely forgot to put that in for the realloc.. – t0mm13b Jan 31 '10 at 18:13
  • @tommieb75, I assume you mean pre-ANSI compilers that used char* for the return of malloc. Else your second comment doesn't make sense, casting a void* to a void*... – Secure Jan 31 '10 at 18:31
  • @Secure: not pre-ansi, Ansi C 89 standard...as for your comment - good point!!! Will edit this accordingly... – t0mm13b Jan 31 '10 at 18:32
  • @Secure: Edited the answer! Hope it makes better sense! :) Thanks for your feedback. :) – t0mm13b Jan 31 '10 at 18:34
  • I found a way to get this done - its linux specific, but it's all I need. There's mmap and mremap functions on linux that one can use to allocate memory ( see flag MAP_ANONYMUS ), and then resize it assuring that it will not be moved. – zajcev Jan 31 '10 at 20:19
  • @zajcev: I am not sure I follow you, mmap is more for IPC rather then anything else, it does not do the same thing as what the C runtime realloc does, mmap is a POSIX function, not a ANSI C runtime function... – t0mm13b Jan 31 '10 at 20:27
  • mmap can be used to allocate memory too, and mremap will try to reallocate memory in place and only move the block if a flag is set – zajcev Feb 03 '10 at 18:16
  • @zajcev: I'm curious, can I see the source for that information as that is a new one to me? Thanks for that interesting tidbit... :) – t0mm13b Feb 03 '10 at 18:54
  • If the new pointer differs from the old pointer, the memory has been moved. So there is a signaling. – ceving Jun 29 '21 at 07:16
5

This is coming a bit late, but the solution to this problem (which nobody has mentioned) is not to use pointers into allocated blocks that will need to be allocated. Instead, use integer-valued offsets from the base pointer or (better) use a struct type and member elements to address specific locations in the allocated object.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Wish I had through of that before I wrote my current assignment. I also think this is part of the answer to zajcev's OP, explaining what he can do about it. – gone Apr 12 '14 at 06:59
4

Yes, cptr will become invalid if realloc moves the block.

No, there is no signal. You would have to check the return value against the original ptr location.

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
3

Yes.

Best thing to do is compare ptr before and after the reallocation, and see if it has been moved. You shouldn't assign a pointer to the offset value, instead you should store the offset and then index the original operator with it.

i.e.

Instead of void* newPtr = ptr + 10; *newPtr = something;

Use int new = 10; ptr[new] = something;

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
2

Yes, the cptr becomes invalid if realloc moves the block.

Samaursa
  • 16,527
  • 21
  • 89
  • 160
bmargulies
  • 97,814
  • 39
  • 186
  • 310