It's clear from the C standards that NULL is an acceptable input to free(), with the result being no operation performed. However, this seems to violate the idea that free() must only be called on memory that was explicitly allocated using malloc(), calloc(), or realloc().
What's the reasoning behind this exception? The only reason I can figure is so that callers do not have to explicitly check for NULL before calling free().
The malloc function (as well as calloc and realloc) may return a NULL pointer if the requested size is 0. Therefore, it makes sense that NULL pointer can also be passed to free since it was returned from a successful call to malloc:
Section 7.22.3p1 of the C standard specifies this behavior:
If the space cannot be allocated, a null pointer is returned. 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.
Related
The C specification says this about the memory allocation 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.
Do all the allocation functions have to be consistent in this regard? Can malloc(0) return a non-null pointer, while realloc(someptr, 0) returns a null pointer?
Can calloc(0, 0) be different from malloc(0)? It would have been simple for the calloc() specification to say that calloc(nmemb, size) is equivalent to malloc(nmemb * size) followed by zeroing the memory, but this equivalence is not explicit.
I created an array of pointers to char. I used malloc(0) to allocate memory for those pointers.
After that, I used scanf() to enter exactly one word to the bytes allocated by malloc(0 and it worked.
Why is that?
First of all, from the man page for malloc(), (emphasis mine)
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
So, it's not guaranteed that malloc(0) will return NULL, always. So, your NULL check may not be a success.
Then, to answer
Why is that?
because, in case malloc(0) returns a pointer other han NULL, it is only fit to be used as an argument to a later call to free(), nothing else. In your case, you're trying to write into the memory. Doing so is essentially attempt to write into an invalid memory, a memory which not allocated to your program. This invokes undefined behavior.
The real beauty of UB is that, sometimes, program invoking UB appear to work just fine.
This question already has answers here:
Freeing allocated memory: realloc() vs. free()
(7 answers)
Closed 9 years ago.
I have tried freeing memory without using free() as below
int *ptr = malloc(20);
realloc(ptr, 0);
Will it work?
C language standards differ on this one: in C90 passing zero size was the same as calling free:
If size is zero, the memory previously allocated at ptr is deallocated as if a call to free was made, and a null pointer is returned.
However, this changed in C99:
If size is zero, the return value depends on the particular library implementation: it may either be a null pointer or some other location that shall not be dereferenced.
Note that freeing is no longer a requirement; neither is returning a NULL when zero size is passed.
realloc(ptr, 0) is not equivalent to free(ptr)
The standard C11 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.
Why because realloc does below things,
It creates new memory of size specified.
Copies contents from old memory to newer.
Frees the old memory
Returns address of new memory
Maybe, but you can't count on it. From the docs:
If new_size is zero, the behavior is implementation defined (null pointer may be returned, or some non-null pointer may be returned that may not be used to access storage).
At least for POSIX: realloc(p, 0) is not the same as free(p).
From the current POSIX documentation on realloc():
Previous versions explicitly permitted a call to realloc (p, 0) to free the space pointed to by p and return a null pointer. While this behavior could be interpreted as permitted by this version of the standard, the C language committee have indicated that this interpretation is incorrect.
so I have a piece of memory allocated with malloc() and changed later with realloc().
At some point in my code I want to empty it, by this I mean essentially give it memory of 0. Something which would intuitively be done with realloc(pointer,0). I have read on here that this is implementation defined and should not be used.
Should I instead use free(), and then do another malloc()?
It depends on what you mean: if you want to empty the memory used, but still have access to that memory, then you use memset(pointer, 0, mem_size);, to re-initialize the said memory to zeroes.
If you no longer need that memory, then you simply call free(pointer);, which'll free the memory, so it can be used elsewhere.
Using realloc(pointer, 0) may work like free on your system, but this is not standard behaviour. realloc(ptr, 0) is not specified by the C99 or C11 standards to be the equivalent of free(ptr).
realloc(pointer, 0) is not equivalent to free(pointer).
The standard (C99, ยง7.22.3.5):
The realloc function
Synopsis
1
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
Description
2 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.
3 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 memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Returns
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.
As you can see, it doesn't specify a special case for realloc calls where the size is 0. Instead, it only states that a NULL pointer is returned on failure to allocate memory, and a pointer in all other cases. A pointer that points to 0 bytes would, then, be a viable option.
To quote a related question:
More intuitively, realloc is "conceptually equivalent" to to malloc+memcpy+free on the other pointer, and malloc-ing a 0-byte chunk of memory returns either NULL either a unique pointer, not to be used for storing anything (you asked for 0 bytes), but still to be freeed. So, no, don't use realloc like that, it may work on some implementations (namely, Linux) but it's certainly not guaranteed.
As another answer on that linked question states, the behaviour of realloc(ptr, 0) is explicitly defined as implementation defined according to the current C11 standard:
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
realloc() is used to increase or decrease the memory and not to free the memory.
Check this, and use free() to release the memory (link).
I don't think you mean "empty"; that would mean "set it to some particular value that I consider to be empty" (often all bits zero). You mean free, or de-allocate.
The manual page says:
If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr).
Traditionally you could use realloc(ptr, 0); as a synonym for free(ptr);, just as you can use realloc(NULL, size); as a synonym for malloc(size);. I wouldn't recommend it though, it's a bit confusing and not the way people expect it to be used.
However, nowadays in modern C the definition has changed: now realloc(ptr, 0); will free the old memory, but it's not well-defined what will be done next: it's implementation-defined.
So: don't do this: use free() to de-allocate memory, and let realloc() be used only for changing the size to something non-zero.
Use free() to free, to release dynamically allocated memory.
Although former documentations state that realloc(p, 0) is equivalent to free(p), the lastest POSIX documentation explictly states that this is not the case:
Previous versions explicitly permitted a call to realloc (p, 0) to free the space pointed to by p and return a null pointer. While this behavior could be interpreted as permitted by this version of the standard, the C language committee have indicated that this interpretation is incorrect.
And more over:
Applications should assume that if realloc() returns a null pointer, the space pointed to by p has not been freed.
Use free(pointer); pointer = 0 instead of realloc(pointer, 0).
void* realloc (void* ptr, size_t size);
In C90 :
if size is zero, the memory previously allocated at ptr is deallocated as if a call to free was made, and a null pointer is returned.
In C99:
If size is zero, the return value depends on the particular library implementation: it may either be a null pointer or some other location that shall not be dereferenced.
I would use realloc to give a pointer more or less memory, but not to empty it. To empty the pointer I would use free.
If you have a pointer that is not initialized and, by mistake, try to free it, is this going to result in undefined behavior?
Like:
int main(void){
char *string;
free(string);
return 0;
}
Does freeing an uninitialized pointer result in undefined behavior?
Yes.
However, freeing a null pointer is well-defined.
From the C99 standard:
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. 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.
Yes, because accessing any uninitialised variable provokes undefined behaviour.
This includes passing an uninitialise pointer tofree(). This itself also includes the case where the uninitialise pointer "by accident" may have a value equal to NULL.
Yes, it is undefined behavior.
The pointer passed to free should be a pointer to a valid object allocated with malloc, calloc, realloc or a null pointer.
From C99:
(7.20.3.2p2) "If ptr is a null pointer, no action occurs. 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."
Yes, it does, since you should only free() a pointer that 1. is NULL or 2. you obtained via a call to malloc(), calloc() or realloc().