Robert said:
I was referring specifically to the behavior of realloc
deallocating the original object which is well defined.
NULL is always a sign of failure when the size provided is
non-zero, if you want to provide a size of zero is is easy
enough to handle the return
What evidence do you have that a non-NULL value returned by
realloc, when provided a size of zero, cannot safely be passed
to free() or realloc()?
As I read the following from N869:
7.20.3 Memory management functions
[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated). Each such allocation shall yield a pointer to
an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the
allocated space. 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. The value of a pointer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
that refers to freed space is indeterminate.
Is freeing NULL so generated accessing an object?
No.
Is freeing non-NULL so generated accessing an object?
No.
When things are buried in layers of code we can easily guarantee
that the pointer was created by malloc/realloc, and we can even
guard it by making it NULL after passing to free, but that guard won't
work if realloc can return a non-freeable pointer.
The pointer returned by calloc/malloc/realloc in any scenerio can always
be passed to free() at least once (only once for non-NULL).
From 7.20.3.2p2, free description:
"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."
According to the description, any pointer returned by calloc, malloc or
realloc that has not already been freed may be passed to free() without
invoking undefined behavior. No special provisions are made for the case
where zero size was passed to the allocation function to generate the
pointer in question.
To further support this position, section 7.20.3 of the Rationale
v5.10 provides the following example:
"The treatment of null pointers and zero-length allocation requests in the
definition of these functions was in part guided by a desire to support
this paradigm:
OBJ * p; // pointer to a variable list of OBJs
/* initial allocation */
p = (OBJ *) calloc(0, sizeof(OBJ));
/* ... */
/* reallocations until size settles */
while(1) {
p = (OBJ *) realloc((void *)p, c * sizeof(OBJ));
/* change value of c or break out of loop */
}
"
In this example, p is assigned the return value of calloc which, since one
of the arguments is zero, according to Standard behaves the same as if
malloc were passed a size of zero. p is now either NULL, or non-NULL
depending on the implementation (or possibly NULL if an error occured).
The value of p is then passed to realloc to increase the size, initially
from zero. If p was NULL from the calloc call, realloc will behave like
malloc. If calloc returned non-NULL, that value is now being passed to
realloc which deallocates the original zero-length object (as free would
do) and allocates more memory, etc.
In short, if an implmentation can "allocate" zero-length objects, it can
also free/realloc them. The effort needed to handle the implementation
defined part seems minimal.
Rob Gamble