I just saw this code:
artist = (char *) malloc(0);
...and I was wondering why would one do this?
According to the specifications, malloc(0) will return either "a null pointer or a unique pointer that can be successfully passed to free()".
This basically lets you allocate nothing, but still pass the "artist" variable to a call to free() without worry. For practical purposes, it's pretty much the same as doing:
artist = NULL;
The C standard (C17 7.22.3/1) says:
If the size of the space requested is zero, the behavior is implementation defined:
either a null pointer is returned, or the behavior is as if the size were some
nonzero value, except that the returned pointer shall not be used to access an object.
So, malloc(0) could return NULL or a valid pointer that may not be dereferenced. In either case, it's perfectly valid to call free() on it.
I don't really think malloc(0) has much use, except in cases when malloc(n) is called in a loop for example, and n might be zero.
Looking at the code in the link, I believe that the author had two misconceptions:
malloc(0) returns a valid pointer always, and
free(0) is bad.
So, he made sure that artist and other variables always had some "valid" value in them. The comment says as much: // these must always point at malloc'd data.
malloc(0) behaviour is implementation specific. The library can return NULL or have the regular malloc behaviour, with no memory allocated. Whatever it does, it must be documented somewhere.
Usually, it returns a pointer that is valid and unique but should NOT be dereferenced. Also note that it CAN consume memory even though it did not actually allocate anything.
It is possible to realloc a non null malloc(0) pointer.
Having a malloc(0) verbatim is not much use though. It's mostly used when a dynamic allocation is zero byte and you didn't care to validate it.
There's an answer elsewhere on this page that begins "malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory". This statement is incorrect (I don't have enough reputation to comment on that answer directly, so can't put this comment directly under there).
Doing malloc(0) will not automatically allocate memory of correct size. The malloc function is unaware of what you're casting its result to. The malloc function relies purely on the size number that you give as its argument. You need to do malloc(sizeof(int)) to get enough storage to hold an int, for example, not 0.
There are a lot of half true answers around here, so here are the hard facts. The man-page for malloc() says:
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
successfully passed to free().
That means, there is absolutely no guarantee that the result of malloc(0) is either unique or not NULL. The only guarantee is provided by the definition of free(), again, here is what the man-page says:
If ptr is NULL, no operation is performed.
So, whatever malloc(0) returns, it can safely be passed to free(). But so can a NULL pointer.
Consequently, writing artist = malloc(0); is in no way better than writing artist = NULL;
malloc(0) doesn't make any sense to me, unless the code is relying on behaviour specific to the implementation. If the code is meant to be portable, then it has to account for the fact that a NULL return from malloc(0) isn't a failure. So why not just assign NULL to artist anyway, since that's a valid successful result, and is less code, and won't cause your maintenance programmers to take time figuring it out?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO) or malloc(some_variable_which_might_be_zero) perhaps could have their uses, although again you have to take extra care not to treat a NULL return as a failure if the value is 0, but a 0 size is supposed to be OK.
Why you shouldn't do this...
Since malloc's return value is implementation dependent, you may get a NULL pointer or some other address back. This can end up creating heap-buffer overflows if error handling code doesn't check both size and returned value, leading to stability issues (crashes) or even worse security issues.
Consider this example, where further accessing memory via returned address will corrupt heap iff size is zero and implementation returns a non NULL value back.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
See this Secure Coding page from CERT Coding Standards where I took the example above for further reading.
Admittedly, I have never seen this before, this is the first time I've seen this syntax, one could say, a classic case of function overkill. In conjunction to Reed's answer, I would like to point out that there is a similar thing, that appears like an overloaded function realloc:
foo is non-NULL and size is zero, realloc(foo, size);. When you pass in a non-NULL pointer and size of zero to realloc, realloc behaves as if you’ve called free(…)
foo is NULL and size is non-zero and greater than 1, realloc(foo, size);. When you pass in a NULL pointer and size is non-zero, realloc behaves as if you’ve called malloc(…)
Hope this helps,
Best regards,
Tom.
In Windows:
void *p = malloc(0); will allocate a zero-length buffer on the local heap. The pointer returned is a valid heap pointer.
malloc ultimately calls HeapAlloc using the default C runtime heap which then calls RtlAllocateHeap, etc.
free(p); uses HeapFree to free the 0-length buffer on the heap. Not freeing it would result in a memory leak.
To actually answer the question made: there is no reason to do that
malloc(0) will return NULL or a valid pointer which can be rightly passed to free. And though it seems like the memory that it points to is useless or it can't be written to or read from, that is not always true. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
We expect a segmentation fault here, but surprisingly, this prints 100! It is because malloc actually asks for a huge chunk of memory when we call malloc for the first time. Every call to malloc after that, uses memory from that big chunk. Only after that huge chunk is over, new memory is asked for.
Use of malloc(0): if you are in a situation where you want subsequent malloc calls to be faster, calling malloc(0) should do it for you (except for edge cases).
Not sure, according to some random malloc source code I found, an input of 0 results in a return value of NULL. So it's a crazy way of setting the artist pointer to NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Its actually quite useful, and (obviously IMHO), the allowed behavior of returning a NULL pointer is broken. A dynamic pointer is useful not only for what it points at, but also the fact that it's address is unique. Returning NULL removes that second property. All of the embedded mallocs I program (quite frequently in fact) have this behavior.
Here is the analysis after running with valgrind memory check tool.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
and here's my sample code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
By default 1024 bytes is allocated. If I increase the size of malloc, the allocated bytes will increase by 1025 and so on.
According to Reed Copsey answer and the man page of malloc , I wrote some examples to test. And I found out malloc(0) will always give it a unique value.
See my example :
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
The output will be "Got a valid pointer", which means ptr is not null.
Just to correct a false impression here:
artist = (char *) malloc(0); will never ever return NULL; it's not the same as artist = NULL;. Write a simple program and compare artist with NULL. if (artist == NULL) is false and if (artist) is true.
malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory. Also you can assign values to the memory area but this should be in range with the type of pointer being used. You can also free the allocated memory. I will explain this with an example:
int *p=NULL;
p=(int *)malloc(0);
free(p);
The above code will work fine in a gcc compiler on Linux machine. If you have a 32 bit compiler then you can provide values in the integer range, i.e. -2147483648 to 2147483647. Same applies for characters also. Please note that if type of pointer declared is changed then range of values will change regardless of malloc typecast, i.e.
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p will take a value from 0 to 255 of char since it is declared an unsigned int.
Related
I just saw this code:
artist = (char *) malloc(0);
...and I was wondering why would one do this?
According to the specifications, malloc(0) will return either "a null pointer or a unique pointer that can be successfully passed to free()".
This basically lets you allocate nothing, but still pass the "artist" variable to a call to free() without worry. For practical purposes, it's pretty much the same as doing:
artist = NULL;
The C standard (C17 7.22.3/1) says:
If the size of the space requested is zero, the behavior is implementation defined:
either a null pointer is returned, or the behavior is as if the size were some
nonzero value, except that the returned pointer shall not be used to access an object.
So, malloc(0) could return NULL or a valid pointer that may not be dereferenced. In either case, it's perfectly valid to call free() on it.
I don't really think malloc(0) has much use, except in cases when malloc(n) is called in a loop for example, and n might be zero.
Looking at the code in the link, I believe that the author had two misconceptions:
malloc(0) returns a valid pointer always, and
free(0) is bad.
So, he made sure that artist and other variables always had some "valid" value in them. The comment says as much: // these must always point at malloc'd data.
malloc(0) behaviour is implementation specific. The library can return NULL or have the regular malloc behaviour, with no memory allocated. Whatever it does, it must be documented somewhere.
Usually, it returns a pointer that is valid and unique but should NOT be dereferenced. Also note that it CAN consume memory even though it did not actually allocate anything.
It is possible to realloc a non null malloc(0) pointer.
Having a malloc(0) verbatim is not much use though. It's mostly used when a dynamic allocation is zero byte and you didn't care to validate it.
There's an answer elsewhere on this page that begins "malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory". This statement is incorrect (I don't have enough reputation to comment on that answer directly, so can't put this comment directly under there).
Doing malloc(0) will not automatically allocate memory of correct size. The malloc function is unaware of what you're casting its result to. The malloc function relies purely on the size number that you give as its argument. You need to do malloc(sizeof(int)) to get enough storage to hold an int, for example, not 0.
There are a lot of half true answers around here, so here are the hard facts. The man-page for malloc() says:
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
successfully passed to free().
That means, there is absolutely no guarantee that the result of malloc(0) is either unique or not NULL. The only guarantee is provided by the definition of free(), again, here is what the man-page says:
If ptr is NULL, no operation is performed.
So, whatever malloc(0) returns, it can safely be passed to free(). But so can a NULL pointer.
Consequently, writing artist = malloc(0); is in no way better than writing artist = NULL;
malloc(0) doesn't make any sense to me, unless the code is relying on behaviour specific to the implementation. If the code is meant to be portable, then it has to account for the fact that a NULL return from malloc(0) isn't a failure. So why not just assign NULL to artist anyway, since that's a valid successful result, and is less code, and won't cause your maintenance programmers to take time figuring it out?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO) or malloc(some_variable_which_might_be_zero) perhaps could have their uses, although again you have to take extra care not to treat a NULL return as a failure if the value is 0, but a 0 size is supposed to be OK.
Why you shouldn't do this...
Since malloc's return value is implementation dependent, you may get a NULL pointer or some other address back. This can end up creating heap-buffer overflows if error handling code doesn't check both size and returned value, leading to stability issues (crashes) or even worse security issues.
Consider this example, where further accessing memory via returned address will corrupt heap iff size is zero and implementation returns a non NULL value back.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
See this Secure Coding page from CERT Coding Standards where I took the example above for further reading.
Admittedly, I have never seen this before, this is the first time I've seen this syntax, one could say, a classic case of function overkill. In conjunction to Reed's answer, I would like to point out that there is a similar thing, that appears like an overloaded function realloc:
foo is non-NULL and size is zero, realloc(foo, size);. When you pass in a non-NULL pointer and size of zero to realloc, realloc behaves as if you’ve called free(…)
foo is NULL and size is non-zero and greater than 1, realloc(foo, size);. When you pass in a NULL pointer and size is non-zero, realloc behaves as if you’ve called malloc(…)
Hope this helps,
Best regards,
Tom.
In Windows:
void *p = malloc(0); will allocate a zero-length buffer on the local heap. The pointer returned is a valid heap pointer.
malloc ultimately calls HeapAlloc using the default C runtime heap which then calls RtlAllocateHeap, etc.
free(p); uses HeapFree to free the 0-length buffer on the heap. Not freeing it would result in a memory leak.
To actually answer the question made: there is no reason to do that
malloc(0) will return NULL or a valid pointer which can be rightly passed to free. And though it seems like the memory that it points to is useless or it can't be written to or read from, that is not always true. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
We expect a segmentation fault here, but surprisingly, this prints 100! It is because malloc actually asks for a huge chunk of memory when we call malloc for the first time. Every call to malloc after that, uses memory from that big chunk. Only after that huge chunk is over, new memory is asked for.
Use of malloc(0): if you are in a situation where you want subsequent malloc calls to be faster, calling malloc(0) should do it for you (except for edge cases).
Not sure, according to some random malloc source code I found, an input of 0 results in a return value of NULL. So it's a crazy way of setting the artist pointer to NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Its actually quite useful, and (obviously IMHO), the allowed behavior of returning a NULL pointer is broken. A dynamic pointer is useful not only for what it points at, but also the fact that it's address is unique. Returning NULL removes that second property. All of the embedded mallocs I program (quite frequently in fact) have this behavior.
Here is the analysis after running with valgrind memory check tool.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
and here's my sample code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
By default 1024 bytes is allocated. If I increase the size of malloc, the allocated bytes will increase by 1025 and so on.
According to Reed Copsey answer and the man page of malloc , I wrote some examples to test. And I found out malloc(0) will always give it a unique value.
See my example :
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
The output will be "Got a valid pointer", which means ptr is not null.
Just to correct a false impression here:
artist = (char *) malloc(0); will never ever return NULL; it's not the same as artist = NULL;. Write a simple program and compare artist with NULL. if (artist == NULL) is false and if (artist) is true.
malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory. Also you can assign values to the memory area but this should be in range with the type of pointer being used. You can also free the allocated memory. I will explain this with an example:
int *p=NULL;
p=(int *)malloc(0);
free(p);
The above code will work fine in a gcc compiler on Linux machine. If you have a 32 bit compiler then you can provide values in the integer range, i.e. -2147483648 to 2147483647. Same applies for characters also. Please note that if type of pointer declared is changed then range of values will change regardless of malloc typecast, i.e.
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p will take a value from 0 to 255 of char since it is declared an unsigned int.
Does realloc mutate its first argument?
Is mutating the first argument dependent on the implementation?
Is there a reason it should not be const? As a counter example memcpy makes its src argument const.
ISO C standard, section 7.20.3 Memory management functions, does not specify. The Linux man page for realloc does not specify.
#include <stdio.h>
#include <stdlib.h>
int main() {
int* list = NULL;
void* mem;
mem = realloc(list, 64);
printf("Address of `list`: %p\n", list);
list = mem;
printf("Address of `list`: %p\n", list);
mem = realloc(list, 0);
printf("Address of `list`: %p\n", list);
// free(list); // Double free
list = mem;
printf("Address of `list`: %p\n", list);
}
When I run the above code on my Debian laptop:
The first printf is null.
The second printf has an address.
The third printf has the same address as the second.
In accordance with the spec, trying to free the address results in a double free error.
The forth printf is null.
The function does not change the original pointer because it deals with a copy of the pointer. That is the pointer is not passed by reference.
Consider the following program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *p = malloc( sizeof( int ) );
*p = 10;
printf( "Before p = %p\n", ( void * )p );
char *q = realloc( p, 2 * sizeof( int ) );
printf( "After p = %p\n", ( void * )p );
free( q );
return 0;
}
Its output is
Before p = 0x5644bcfde260
After p = 0x5644bcfde260
As you see the pointer p was not changed.
However the new pointer q can have the same value as pointer p had before the call of realloc.
From the C Standard (7.22.3.5 The realloc function)
4 The realloc function returns a pointer to the new object (which
may have the same value as a pointer to the old object), or a null
pointer if the new object could not be allocated.
Of course if you will write
p = realloc( p, 2 * sizeof( int ) );
instead of
char *q = realloc( p, 2 * sizeof( int ) );
then it is evident that in general the new value of pointer p can differ from the old value of p (though can be the same according to the quote). For example if the function was unable to reallocate memory. In this case a memory leak will occur provided that initial value of the pointer p was not equal to NULL. Because in this case (when the initial value of the pointer was not equal to NULL) the address of the early allocated memory will be lost.
The old memory is not deallocated if a new memory extent can not be
allocated because the function needs to copy the old content to the
new extent of memory.
From the C Standard (7.22.3.5 The realloc function)
If memory for the new object cannot be allocated, the old object is
not deallocated and its value is unchanged.
Pay attention to that this call
mem = realloc(list, 0);
does not necessary return NULL.
From the C Standard (7.22.3 Memory management functions)
If the size of the space requested is zero, the behavior is
implementation-defined: either a null pointer is returned, or the
behavior is as if the size were some nonzero value, except that the
returned pointer shall not be used to access an object.
First of all, formally, realloc frees the memory pointed to by its first argument after allocating a new object and copying the contents. As such, semantically it's absolutely correct that the pointed-to type not be const qualified. In limited cases, the new object's address may be the same as the old object's address, but a correct program largely can't even see this (comparing against the old pointer is undefined behavior), much less depend on it.
Secondly, I think you're confusing the const-ness of the argument type and the pointed-to type. const on argument types makes no sense whatsoever (and is ignored by the language, except in the implementation of the called function where it makes the local variable receiving the argument constant) since arguments are always values, not references to some object in the caller. Of course realloc can't change the value of the caller's pointer variable you pass to it. However, due to any use of invalid pointers being undefined behavior, your program can (because UB allows anything) exhibit behavior as if the caller's copy had been modified. For example, comparing it for equality with the new pointer may give inconsistent results. The const on memcpy's src makes a pointer-to-const type, not a const type.
realloc() can free the memory that its argument points to, if it can't reuse the same memory. I think this is considered to be like a mutation (since it effectively destroys it completely).
Semantically, realloc() is equivalent to:
void *realloc(void *ptr, size_t size) {
void *result = malloc(size);
if (result && ptr) {
memcpy(result, ptr, min(size, _allocation_size(ptr)));
free(ptr);
}
return result;
}
where _allocation_size() is some internal function of the C runtime that determines the size of a dynamic memory allocation.
Since the argument to free() is not declared const void *, neither is the first argument to realloc().
I'm not entirely sure what you mean by "Does realloc mutate its first argument?".
It certainly doesn't change the value of the pointer in the caller -- no C function can do that.
But does it alter the value of the pointed-to memory? That's a trickier question.
As far as the programmer is concerned, you hand realloc a pointer to M bytes, and it returns you a (possibly different) pointer to N bytes.
If it hands you back the same pointer (meaning that it was able to do the reallocation "in place"), and if N ≥ M, it definitely does not touch the M former bytes.
If it hands you back the same pointer but N < M (that is, if you reallocated the region smaller), you're no longer allowed to access or even ask about the bytes beyond M, so it's particularly hard to say whether they were modified. (But in fact, they might well have been modified, in the process of marking them unused, and available for future allocation).
Finally, if realloc hands you back a different pointer, the M former bytes are "gone" -- again, you're no longer allowed to access them, so it's hard to say if they were modified, but they probably were, because all of them are now available for future allocation.
But in any case: the pointer you hand to realloc is a pointer into the heap, and realloc definitely alters the heap as it does its work, so yes, I think it's safe to say that realloc mutates its first argument, which therefore should not be declared const. (Even in the first case I discussed, where realloc "definitely did not touch the M former bytes", it probably did still adjust some nearby data structures, to record the new allocation.)
And, finally, if by "mutate" you mean the sort of thing that C++ programs are allowed to do when member variables are declared mutable -- that is, a change happens behind the scenes to some data structure referenced by a pointer that was otherwise qualified const -- well, yes, that's not too far off from what realloc does. If realloc's first argument were const, and if the modifications realloc did perform were to data structures qualified as mutable, then I suppose this would work -- but also if we were talking about C++.
But of course we're not talking about C++; we're talking about C, which doesn't even have the mutable qualifier.
(I'd say memcpy isn't a counterexample, because it doesn't do anything that even remotely smells like writing to any data structures associated with its second argument.)
Does realloc mutate its first argument?
If you mean change the value of the variable passed as parameter the answer is no. The point isn't related to the specific realloc() function, but more generally to the way used by the language to handle parameters. C language produce a private copy of each argument, typically on the stack, before to pass them to the function, For this reason each change to them is confined locally and is lost when the function returns and the stack reused. Formally the C language pass almost all types by value (arrays are a well known exception). Anyway I'll come back on the argument below.
Is mutating the first argument dependent on the implementation?
Of course not. As said above this depends by the language.
Is there a reason it should not be const? As a counter example memcpy
makes its src argument const.
Of course there is a reason.
Forget about void * memcpy ( void * destination, const void * source, size_t num ) that has no connection to void* realloc (void* ptr, size_t size), lets consider that the management of dynamic memory depends on specific local implementation, but basically all allocation routines are based on memory pools, normally divided in small chunks, from where are derived the memory blocks returned to our programs. We can imagine that when we require to shrink the block the system will remove some chunks giving back a smaller block that incidentally remain at the same address, but if we require an extension maybe the chunks following our block are already assigned we can't proceed.
On an embedded 8 bit micro may happen that the actual memory block cannot be extended, but that another memory area is large enough for the scope, in that case we can copy the former block data to the new one and return it. But in this case we have a different address in memory.
But the malloc() must be universal independently from the machine where it is implemented, starting from 8 bits embedded applications to 64bits desktops with GBytes of available memory and virtual memory support. For this reason the standard must provide a definition that could fit all cases.
The second point is how pass the result, pass/fail, of the reallocation, if would have been used a reference to the memory block pointer (ie passing &ptr), in case of a failure returning NULL the original pointer would have been lost!. The user, to preserve it, must have done a copy of the pointer before to realloc(), but this procedure is unnatural e prone to errors.
For this reason in the standard library the problem is approached from a different side: the reallocation will formally return always a freshly allocated memory block in which has been copied the former memory block data. The programmer is required only to check the result before use it (see below code example).
The standard is very clear in the function definition, as already mentioned in other answers, that for sake of completeness I report below. From ISO/IEC 9899:2017 §7.22.3.5 The realloc function:
The realloc function deallocates the old object pointed to by ptr and
returns a pointer to a new object that has the size specified by size.
The contents of the new object shall be the same as that of the old
object prior to deallocation, up to the lesser of the new and old
sizes.
Any bytes in the new object beyond the size of the old object have
indeterminate values.
If ptr is a null pointer, the realloc function behaves like the malloc
function for the specified size. Otherwise, if ptr does not match a
pointer earlier returned by a memory management function, or if the
space has been deallocated by a call to the free or realloc function,
the behavior is undefined.
If size is nonzero and memory for the new object is not allocated, the
old object is not deallocated.
If size is zero and memory for the new object is not allocated, it is
implementation-defined whether the old object is deallocated. If the
old object is not deallocated, its value shall be unchanged.
The realloc function returns a pointer to the new object (which may
have the same value as a pointer to the old object), or a null pointer
if the new object has not been allocated.
Because you don't know if realloc() returns a new object or the former one, or even NULL in case of error, you should consider realloc() as always returning a new object, hence the code:
int* list = NULL;
void* mem;
mem = realloc(list, 64);
printf("Address of `list`: %p\n", list);
Is wrong at least for two reasons:
Obviously Because if realloc() return a new object and frees the
old memory, the variable list contains an invalid pointer. Moreover it could fail returning NULL, in that case the former block will still be valid.
Because you can't expect to have list changed in any way passing it as a local parameter in a function. Of course list will retain its former value that is NULL.
While passing a null pointer to realloc() is standard compliant, because it explicitly says that in this case the behavior will be the same as malloc(), passing a zero size the behavior is implementation-defined implying that the former block will be deallocated by some compilers, but not from some others. The latter means that the behavior can change on compiler basis, on your machine we can deduce that evidently the compiler behavior is to deallocate the block because of the double free error you got and the null pointer returned by realloc(). Please note also that in latter case when passing a zero size to realloc()the returned NULL could not mean that a failure occurred, and that the function was successful, but in case of failure you will not able to correctly understand if there was a failure or not. This is an ambiguity of the function (or it is so at my knowledge comments are welcome).
The golden rules to follow when using realloc() are basically these:
Keep in mind that the object returned from function is always a
new object and you have to save it.
Because realloc() can fail and return a NULL pointer, never use
code as that below, because if it fails we will overwrite the old
object pointer loosing the possibility to recover data or free the
former object. Always use a temporary variable to check the return
value.
Example code:
void *p = malloc(SIZE);
/* Wrong approach we overwrite anyway teh pointer */
p = realloc(p, 2*SIZE);
/** Correct approach */
void *pTmp = realloc(p, 2*SIZE);
if (NULL == pTmp)
{
//Error manage code
}
else
{
p = pTmp; //assign value
}
Now you may ask why on many machines, having virtual memory management as desktops, smartphones and the like, often happen to have unchanged memory address returned from realloc(). Well the point is that, thanks to the virtual memory management, more physical not contiguous memory chunks can be added to the virtual memory chain, then the virtual memory descriptors can be manipulated, mapping consequential virtual addresses to each physical chunk in such a way that the user sees a flat contiguous virtual memory space.
I am now studying C and in some code examples I saw that after we allocate some memory to a pointer, we have to check the pointer to be not a NULL. For example:
CVector *vector = malloc(sizeof(struct CVectorImplementation));
assert(vector != NULL);
another example:
vector->elements = realloc(vector->elements, vector->elemsz * vector->vec_capacity);
assert(vector->elements != NULL);
However, I think since the pointer is already been allocated, then it has the address of the allocated memory as its value, thus is it always necessary? why?
If you've reassigned the original pointer in response to realloc, it's too late to do anything useful in response to a failure. When realloc fails, it returns NULL, but it does not free the original pointer. So even if you have some reasonable response to an allocation failure (not common), you've already leaked the memory you were trying to realloc.
The answer to your main question is mostly "it's a bad idea to allow NULL pointer dereferences to occur because it's a source of vulnerabilities"; usually the vulnerabilities crop up in kernel code (where NULL is just as valid an address as anywhere else), but even when it's not exploitable, it means the program segfaults instead of reporting an error in a useful way.
It's a great idea to check the pointer returned from malloc/realloc.
If there's an error, you will get a null value returned. Use this check to your advantage because if you make reference to the same pointer later in your program and your program suddenly crashes, then chances are the pointer is set to null.
If you do have a valid pointer from a malloc/realloc call, then make sure you use it inside the free() function before deciding to modify the pointer value and before the program terminates, otherwise, you may run into memory leaks.
If you need to change the pointer value to write to a different section of the memory you allocated, then use another pointer.
Here's code in C that shows what I mean:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *block=calloc(1,10000);
if (block==NULL){
printf("Can't allocate memory\n");
return -1;
}
memset(block,48,20); //set 1st 20 bytes of memory to number zero (ascii code 48)
char *insideoftheblock=block+10; // I set a pointer to go to index #10 in the memory
*insideoftheblock='x';
*insideoftheblock++;
*insideoftheblock='y';
printf("Memory = '%s'",block);
free(block);
}
P.S.
I updated my code to include a check to see if memory has been actually allocated.
The realloc function attempts to allocate new memory. If this allocation fails then the realloc function returns NULL. Your code must deal with this situation.
If you want to abort your program in this case then the assert as you currently have it is suitable. If you want to recover, then you will need to store the realloc result in a separate variable while you assess the situation, e.g.:
void *new = realloc(vector->elements, vector->elemsz * vector->vec_capacity);
if ( !new )
// take some action.... the old vector->elements is still valid
else
vector->elements = new;
A failed allocation typical results in 1 of 2 actions:
1) Exit the program with a diagnostic. This is far better than not checking and letting the code continue to who--knows--what.
2) In select circumstances, code can cope with the failure. Maybe freeing other resources and trying again, return a failure code and leave the problem to the calling routine or writing a "suicide note" and re-starting the system. IAC, the action is very specific to the situation.
Robust code checks the result. Beginner code does not.
Can anyone summarize what is the correct usage of realloc()?
What do you do when realloc() fails?
From what I have seen so far, it seems that if realloc() fails, you have to free() old pointer. Is that true?
Here is an example:
1. char *ptr = malloc(sizeof(*ptr) * 50);
2. ...
3. char *new_ptr = realloc(ptr, sizeof(*new_ptr) * 60);
4. if (!new_ptr) {
5. free(ptr);
6. return NULL;
7. }
Suppose realloc() fails on line 3. Am I doing the right thing on line 5 by free()ing ptr?
From http://www.c-faq.com/malloc/realloc.html
If realloc cannot find enough space at all, it returns a null pointer, and leaves the previous region allocated.
Therefore you would indeed need to free the previously allocated memory still.
It depends on what you want to do. When realloc fails, what is it you want to do: free the old block or keep it alive and unchanged? If you want to free it, then free it.
Keep in mind also, that in C89/90 if you make a realloc request with zero target size, realloc function may return a null pointer even though the original memory was successfully deallocated. This was a defect in C89/90, since there was no way to tell the success from failure on null return.
In C99 this defect was fixed and the strict relationship between null return and success/failure of reallocation was guaranteed. In C99 null return always means total failure of realloc.
If realloc fails I don't think you would want to delete the original block since you will lose it. It seems like realloc will resize the old block (or return a pointer to a new location) and on success will return a pointer to the old block (or new location) and on failure will return NULL. If it couldn't allocate a new block the old block is untouched.
Edit: Correction, some people are bashing me for what I said, the way you allocated your pointer seems to be best practice among them, I was taught to always go with type casts in the sizeof(), but apparently your way is more correct, so disregard what I said =)
Taking a peek at http://en.wikipedia.org/wiki/Malloc#realloc before might have done you some good.
You don't quite understand sizeof() - it has the value of the size of the argument you pass to it in bytes. For example, sizeof(int) will be 4 on most 32 bit systems but you should still use sizeof(int) instead of 4 because compiling your code on a 64 bit system (just as an example) will make that value equal to 8 and your code will still compile fine. What are you allocating memory for? Pointers? If so you should use sizeof(void*) instead (you can say sizeof(int*) but it's common convention not to mention to the compiler what you want to store at those pointers, since all pointers should be the same size - so most programmers say sizeof(void*)), if you need space for characters use sizeof(char) and so on.
You are however right to store the return value of realloc() in a new pointer and check it, though a lot of programmers will assume the system always has enough memory and get away with it.
This question already has answers here:
What's the point of malloc(0)?
(17 answers)
Closed 8 years ago.
Very simple question, I made the following program :
#include <stdlib.h>
int main(int argc, char ** argv)
{
void * ptr;
ptr = malloc(0);
free(ptr);
}
And it does not segfault on my machine. Is it a portable behaviour of stdlib malloc and free, or am I looking for trouble ?
Edit : What seems non portable is the value returned by malloc. The question is about the malloc(0) + free combination, not the value of ptr.
The behaviour is implementation defined, you will receive either a NULL pointer or an address. Calling free for the received pointer should however not cause a problem since:
free(NULL) is ok, no operation is done
free(address) is ok, if address was received from malloc (or others like calloc etc.)
It's allowed to return NULL, and it's allowed to return a non-NULL pointer
you can't dereference. Both ways are sanctioned by the standard (7.20.3):
If the size of the space requested is zero, the behavior is
implementation-defined: either a null pointer is returned, or the
behavior is as if the size were some nonzero value, except that the
returned pointer shall not be used to access an object.
Sorry for the trouble, I should have read the man pages :
malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size is 0, then malloc() returns either NULL, or a
unique pointer value that can later be successfully passed to free().
free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if
free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
It seems it is true at least for the gnu libc
According to the c standard
7.20.3
If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
Though it might be legal C/C++, it is indicative a bigger problems. I generally call it 'pointer slopiness'.
See "Do not make assumptions about the result of malloc(0) or calloc(0)", https://www.securecoding.cert.org/confluence/display/seccode/VOID+MEMxx-A.+Do+not+make+assumptions+about+the+result+of+malloc%280%29+or+calloc%280%29.
Updated taking into account libt & Pax's comments:
The behaviour of calling malloc(0) is implementation dependant or in other words non-portable and undefined.
Link to CFaq question for more detail.
In my experience, I have seen that malloc (0) returns a pointer which can be freed.
But, this causes SIGSEGV in later malloc() statements.
And this was highly random.
When I added a check, for not to call malloc if size to be allocated is zero, I got rid of this.
So, I would suggest not to allocate memory for size 0.
-Ashutosh