This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: glibc realloc(ptr, 0) vs. C17 specification


On 8/6/19 2:58 PM, DJ Delorie wrote:
> 
> for realloc(ptr, 0), I read it this way:
> 
>> If size is zero and memory for the new object is not allocated, it is
>> implementation-defined whether the old object is deallocated.
> 
> We define it as "the old object is deallocated"
> 
>> 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.
> 
> We return a NULL poiner as a new object is not allocated.
> 
>> C17 7.31.12 Invoking realloc with a size argument equal to zero is an
>> obsolescent feature.
> 
> And the user shouldn't be doing this anyway.
> 
> I don't see where the conflict is.  Am I missing something?

Yes:

> C11 7.22.3 (overview): 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.

Which, when read carefully, permits the implementation to define
situations where it returns NULL on success.

> C17 7.22.3.1 (overview): If the size of the space requested is zero, the
> behavior is implementation-defined: either a null pointer is returned to
> indicate an error, 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.

Which has an added phrase: "a null pointer is returned to indicate an
error"; read strictly, the implementation is NOT allowed to return NULL
except on error, but glibc's realloc(ptr,0) returns NULL without setting
errno.  And POSIX wants to ensure that anywhere a C function returns an
error, then errno is reliably set.

Of course, the more specific realloc section in 7.22.3.5 does sound like
an implementation can get away with returning NULL on success, but since
this contradicts the overview section 7.22.3.1, it is hard to decipher
the intent.  And that contradiction is what is new to C17.

Whether that was the intended result of WG14's Defect 400 is unclear,
but we probably need WG14 to answer a new defect to clear up what IS
intended, to make sure that the Austin Group does not mandate something
that will be incompatible with C17 or glibc behavior, and/or whether
glibc is even willing to consider having a versioned realloc which
behaves differently for C17/POSIX8 than for C99/C11/POSIX7.  Knowing
what glibc is willing or unwilling to do may help sway whether the
Austin Group can add a restriction above-and-beyond C that would require
realloc(ptr,0) to either always match what malloc(0) does (if the former
always returns NULL with errno of EINVAL because 0-sized objects are not
supported then so must the latter; if the former returns a non-NULL
object or fails with errno of ENOMEM, but never returns NULL without
touching errno, then so must the latter) or to always fail with errno of
EINVAL (because C17 said realloc with size 0 is obsolescent, and making
it always fail is an easy way to get code to quit relying on whatever
random semantics it used to have in older setups), but adding either of
those restrictions would mean that realloc(ptr,0) can no longer be
glibc's current synonym for free(ptr) without a matching malloc attempt.

There are other places where POSIX already places restrictions
above-and-beyond C, such as requiring errno to be reliably set anywhere
that the C standard requires a function to fail; or requiring the NULL
macro to expand to something with explicit void* type as in '#define
NULL ((void*)0)' rather than the looser C rule which permits '#define
NULL 0'; or requiring function pointers to be convertable to void* and
back without loss of information for the sake of dlsym(), or requiring
'char' to be exactly 8 bits, etc.  But while documenting which errno
values realloc will set is a place where POSIX already restricts beyond
what C says, the question of whether placing new restrictions on
realloc(x, 0) is appropriate is still up for debate.

My personal take is that the Austin Group should permit existing glibc
behavior insofar as glibc behavior doesn't violate C17.  Placing a
restriction beyond C that would require a versioned realloc in glibc is
not a good idea unless glibc developers first agree to be willing to go
that route - so arguments describing pros and cons of glibc even
considering a versioned realloc are helpful.   Florian has already given
one argument against a versioned realloc based on the frequency of
malloc interposition - given that there are already a number of
libraries that replace malloc with their own implementation (whether for
performance reasons such as jemalloc, tcmalloc; or for debug reasons
such as valgrind), because having to replace two different versions of
realloc across multiple implementations just makes life even more
complicated.  But it's a tough call when I can't decipher whether C17 is
self-consistent, and therefore can't state whether glibc is compliant as-is.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]