Is It Safe to Realloc Memory Allocated with New

Is it safe to realloc memory allocated with new?

You can only realloc that which has been allocated via malloc (or family, like calloc).

That's because the underlying data structures that keep track of free and used areas of memory, can be quite different.

It's likely but by no means guaranteed that C++ new and C malloc use the same underlying allocator, in which case realloc could work for both. But formally that's in UB-land. And in practice it's just needlessly risky.


C++ does not offer functionality corresponding to realloc.

The closest is the automatic reallocation of (the internal buffers of) containers like std::vector.

The C++ containers suffer from being designed in a way that excludes use of realloc.


Instead of the presented code

int* data = new int[3];
//...
int* mydata = (int*)realloc(data,6*sizeof(int));

… do this:

vector<int> data( 3 );
//...
data.resize( 6 );

However, if you absolutely need the general efficiency of realloc, and if you have to accept new for the original allocation, then your only recourse for efficiency is to use compiler-specific means, knowledge that realloc is safe with this compiler.

Otherwise, if you absolutely need the general efficiency of realloc but is not forced to accept new, then you can use malloc and realloc. Using smart pointers then lets you get much of the same safety as with C++ containers.

Is it safe to use the realloc after the new operator in C++?

No, the behaviour is undefined. You can only call delete[] on a pointer that you've obtained from a call to new[].

Using std::vector would cause all these memory issues to fall away.

Is it safe to call realloc() on the pointer you pass into function itself?

(1) To answer the question of your title: no it is not, because realloc can give you a different pointer.

(2) To answer the question of your code: Neither. If realloc returns 0, meaning it can not honor your request to increase the size, you have lost your value of string but your old string has not been deallocated (memory leak).

Ad. 1: if you could realloc inside a function then you must either pass a double pointer or return the object.

Ad. 2: an example is:

char *string, *tmp;
string = malloc(5 * sizeof(char));

...

if ((tmp = realloc(string, 10 * sizeof(char))) == 0) {
printf("Could not allocate more memory\n);
return;
}
else
string= tmp;

Is it safe to use realloc?

The first of the two linked article raises two complaints above and beyond the "check the call succeeded" points already raised here.

When this is done, the old contents are discarded and left in memory somewhere. For secure memory applications where it is important to erase all traces of data, this behavior is inappropriate.

This is a valid point if you happen to be storing sensitive data (e.g. private keys, unhashed(!) passwords etc.) and want to make it harder for exploits to recover the data or other processes on the system to steal the data.

Since it moves memory around, any old pointers to that memory become invalid and could cause the program to crash or otherwise misbehave.

This point seems like nonsense to me. Their proposed solution is no better, they malloc(), copy and then free() the original which has the same net effect - the address has changed. If you wanted to avoid moving the memory you might be able to use some platform specific calls to do that, if you arranged for there to be sufficient free address space near them. If you knew a priori how much address space to reserve then you'd probably not be thinking of calling realloc() in the first place though!

If you're gambling on realloc() never moving, always growing then you've probably got bigger problems to worry about anyway and switching to malloc() + copy + free() can't possibly solve that.


Besides the "check your return value properly point", the most interesting point from the second article is a warning about:

Do not realloc your buffer by 1 byte at a time.

they warn:

This is guaranteed to churn your memory heap

This is a potentially valid point, but it's not a criticism of realloc() itself; the same would happen if you used malloc()+copy+free(). The real fix is to grow buffers sensibly regardless of how you grow them or better yet allocate in correct sized chunks up front.

They also have a point about

Using realloc to return memory to the system.

They're correct here in that using any size other than 0 might not actually make a return. It probably makes things no worse, but this usage still seems like an example of premature "optimisation". The fix again is to use sensible sized allocations to begin with.

Sort answer: it's not unsafe, but it's not a magical solution to all your problems either.

Is it safe to always reallocate memory before freeing it - C++

You can't realloc stack memory - so you still have undefined behavior.

The realloc(3) man page will tell you this:

Reallocates the given area of memory. It must be previously allocated
by malloc(), calloc() or realloc() and not yet freed with a call to
free or realloc. Otherwise, the results are undefined.

Is it safe to free() memory allocated by new?

You are not allowed to mix and match malloc and free with new and delete the draft C++ standard refers back to the C99 standard for this and if we go to the draft C++ standard section 20.6.13 C library it says (emphasis mine going forward):

The contents are the same as the Standard C library header stdlib.h, with the following changes:

and:

The functions calloc(), malloc(), and realloc() do not attempt to allocate storage by calling ::operator
new() (18.6).

and:

The function free() does not attempt to deallocate storage by calling ::operator delete().
See also: ISO C Clause 7.11.2.

and includes other changes, none of which state that we can use free on contents allocated with new. So section 7.20.3.2 The free function from the draft C99 standard is still the proper reference and it says:

Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

Does realloc overwrite old contents?

Don't worry about the old contents.

The correct way to use realloc is to use a specific pointer for the reallocation, test that pointer and, if everything worked out ok, change the old pointer

int *oldpointer = malloc(100);

/* ... */

int *newpointer = realloc(oldpointer, 1000);
if (newpointer == NULL) {
/* problems!!!! */
/* tell the user to stop playing DOOM and retry */
/* or free(oldpointer) and abort, or whatever */
} else {
/* everything ok */
/* `newpointer` now points to a new memory block with the contents of oldpointer */
/* `oldpointer` points to an invalid address */
oldpointer = newpointer;
/* oldpointer points to the correct address */
/* the contents at oldpointer have been copied while realloc did its thing */
/* if the new size is smaller than the old size, some data was lost */
}

/* ... */

/* don't forget to `free(oldpointer);` at some time */

How can I use realloc function without discarding the old memories

An example incorporating all improvements suggested in the comments and avoiding the use of global variables, and freeing all allocated memory before the program exits. There is only a need to hold the terminal window open on windows, so conditionally enclose the system("pause");.

Putting it altogether, you would have:

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

int *double_ptr (int *ptr, int *ptrsz) /* pass needed information as parameters */
{
int *newptr = malloc (2 * *ptrsz * sizeof *newptr); /* allocate new block of mem */

if (newptr) { /* validate allocation */
memcpy (newptr, ptr, *ptrsz * sizeof *ptr); /* copy to new block of mem */
*ptrsz *= 2; /* update allocated size */
}

return newptr; /* return pointer */
}

void print (int *ptr1, int *ptr2) /* pass needed information as parameters */
{
/* only one call to printf required */
printf ("ptr1 -> %p, *ptr1 = %d\nptr2 -> %p, *ptr2 = %d\n\n",
(void*)ptr1, *ptr1, (void*)ptr2, *ptr2);
}

int main (void) {

int *ptr1 = NULL, *ptr2 = NULL, lenPtr1 = 10; /* avoid global variables */

if (!(ptr1 = malloc (lenPtr1 * sizeof *ptr1))) { /* validate EVERY allocation */
perror ("malloc-ptr");
return 1;
}
ptr2 = ptr1; /* pointer 1 and 2 hold same address where 10 is stored in memory */
*ptr1 = 10;

printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);

if (!(ptr1 = double_ptr (ptr1, &lenPtr1))) { /* double size of ptr1 */
perror ("malloc-double-ptr1");
return 1;
}

printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);

free (ptr1); /* free allcoated memory */
free (ptr2);

#if defined (_WIN32) || defined (_WIN64)
system("pause");
#endif
}

Example Use/Output

$ ./bin/doubleptrsz
lenPtr1: 10
ptr1 -> 0xb18260, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10

lenPtr1: 20
ptr1 -> 0xb186a0, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10

Let me know if you have further questions.



Related Topics



Leave a reply



Submit