On Wed, Jun 25, 2025 at 03:58:31AM +0200, Alejandro Colomar wrote:
> Hi!
> 
> Here's a revision addressing a few things:
> 
...
> Rationale

> 
>       However, this doesn't need to be like that.  The traditional
>       implementation of realloc(3), present in Unix V7, inherited by
>       the BSDs, and currently available in range of systems, including
>       musl libc, doesn't have any issues.  glibc --which an
>       independent implementtion, not a Unix derivative-- also had this

Typos.  Maybe:

glibc --which uses an independent implementation rather than a Unix
derivative--

>       behavior originally; it changed to the current behavior in 1999
>       (glibc 2.2), only for compatibility with C89, even though
>       ironically C99 was released soon after and made it
>       non-conforming.

glibc 2.2 was released Nov 2000; the change to realloc made it into
2.1.1 of May 1999.  Elsewhere, you are clear that it it glibc <= 2.1
that has the old behavior.  Maybe it's worth being more precise to
name it glibc 2.1.1 here (yes, I know that Paul Eggert originally
mentioned 2.2 in this thread and I've carelessly copied that value; I
guess this is evidence that glibc's version numbering policy has
changed slightly over the years).

I'm still not completely convinced that C99 declares the glibc
behavior to be non-conforming.  On the one hand, it does have the
escape clause of "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." in
7.20.3, with no clause requiring a null pointer return to be treated
as an error.  On the other hand, it has both of these sentences on
realloc proper in 7.20.3.4: "If memory for the new object cannot be
allocated, the old object is not deallocated and its value is
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 could not be allocated."  So if you can
argue that a null pointer being returned MUST imply allocation
failure, it logically follows that allocation failure MUST imply the
original pointer was not deallocated (but glibc deallocated that
pointer, hence non-compliance); but the counter-argument is that if
the implementation defined that returning NULL is possible for reasons
other than allocation failure (which glibc has done), then an
application aware of the implementation-defined behavior can
distinguish between whether a NULL return implies that the old pointer
was deallocated (in glibc's case, the documentation is that errno will
be ENOMEM on allocation failure, and unchanged on the realloc(p,0)
successfully freeing a pointer).  It is not obvious whether the C99
wording claims to have exhaustively listed all possible return types
into just two buckets, or whether it has has merely listed the two
possibilities that apply only to unconditional requirements, while
leaving a third possibility (namely, the return value when the
implementation-defined behavior has kicked in) unwritten.

Therefore, I'm not sure whether a blanket statement that glibc is
non-compliant to C99 will help; can you instead word it along the
lines of "There is an unsettled debate on whether glibc's behavior is
a compliant use of implementation-defined behavior for a size of zero
or a non-compliant case of returning NULL for more than just an
allocation failure"?  I don't think weakening this sentence along
these lines will negatively impact the overall call for C2y to tighten
behavior going forward.  Rather, it is easy to defend as fact that
there is (still!) a community debate (just point to this thread!) and
easy enough to call out two possible interpretations; and that comes
across as less argumentative than declaring as fact that glibc is
either compliant or non-compliant.  Choosing a side alienates people
who have the opposite view, while acknowledging that there are (at
least) two possible viewpoints lets people of both persuasions still
feel included.  (Declaring compliance becomes a lot easier if you can
state that "implementation abc fails standards-conformance text xyz" -
but I'm not sure anyone can point to a comprehensive industry-accepted
standards-conformance test for C99 compliance; the POSIX folks _do_
have a standards conformance test suite, but then you have the problem
that most vendors that have tried to pass that have not been using
glibc)

> 
> Proposed wording
>       Based on N3550.
> 

>       @@ p3
>        If <tt>ptr</tt> is a null pointer,
>        the <b>realloc</b> function behaves
>        like the <b>malloc</b> function for the specified size.
>        Otherwise,
>        if <tt>ptr</tt> does not match a pointer
>        earlier returned by a memory management function,
>        or
>        if the space has been deallocated
>        by a call to the <b>free</b> or <b>realloc</b> function,
>       ## We can probably remove all of the above, because of the
>       ## behavior now being defined as-if by calls to malloc(3) and
>       ## free(3).  But let's do that editorially in a separate change.
>       -or
>       -if the size is zero,
>       ## We're defining the behavior.
>        the behavior is undefined.
>        If
>       -memory for the new object is not allocated,
>       +the space cannot be allocated,
>       ## Editorial; for consistency with the wording of the other functions.
>        the old object is not deallocated
>        and its value is unchanged.
>       +XXX)
> 
>       @@ New footnote XXX
>       +XXX)
>       +While atypical,
>       +<b>realloc</b> may fail
>       +for a call that shrinks the block of memory.

Is it worth wording this as "may fail or return a different pointer
for a call that shrinks the block of memory"?

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization:  qemu.org | libguestfs.org


Reply via email to