On Mon, Jun 16, 2025 at 11:44:53PM +0200, Alejandro Colomar wrote:
> How about I write a proposal to the committee, in which I talk about the
> current situation, and how glibc and Bionic are the only broken
> implementation, and propose a change to ISO C which blesses the behavior
> of all other implementations, rendering glibc and Bionic non-conforming?
> I can then propose a very explicit question:
> 
>       If glibc and Bionic agreed to change their behavior according to
>       this proposal, would the C Committee agree to this change?
> 
> And then come back to glibc with that.  If I get such a conditional
> approval of such a proposal, would glibc then apply the fix?

Hi all,

Here's a draft of a proposal.  Please let me know: if the C Committee
voted yes to the question in this proposal, would glibc change behavior?
See the proposal below.


Have a lovely night!
Alex

---
Name
        alx-0029r0 - realloc(p,0) should be consistent with malloc(0)

Principles
        -  Codify existing practice to address evident deficiencies.
        -  Enable secure programming

Category
        Remove UB

Author
        Alejandro Colomar <a...@kernel.org>

        Cc: наб <nabijaczlew...@nabijaczleweli.xyz>
        Cc: Douglas McIlroy <douglas.mcil...@dartmouth.edu>
        Cc: Paul Eggert <egg...@cs.ucla.edu>
        Cc: Bruno Haible <br...@clisp.org>
        Cc: Robert Seacord <rcseac...@gmail.com>
        Cc: JeanHeyd Meneide <phdoftheho...@gmail.com>
        Cc: Elliott Hughes <e...@google.com>
        Cc: Rich Felker <dal...@libc.org>
        Cc: Adhemerval Zanella Netto <adhemerval.zane...@linaro.org>
        Cc: Joseph Myers <josmy...@redhat.com>
        Cc: Florian Weimer <fwei...@redhat.com>
        Cc: Wilco Dijkstra <wilco.dijks...@arm.com>
        Cc: DJ Delorie <d...@redhat.com>
        Cc: Siddhesh Poyarekar <siddh...@gotplt.org>
        Cc: Sam James <s...@gentoo.org>

History
        <https://www.alejandro-colomar.es/src/alx/alx/wg14/alx-0029.git/>

        r0 (2025-06-17):
        -  Initial draft.

See also
        <https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
        
<https://inbox.sourceware.org/libc-alpha/nbyurzcgzgd5rdybbi4no2kw5grrc32k63svf7oq73nfcbus5r@77gry66kpqfr/>
        
<https://inbox.sourceware.org/libc-alpha/qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv/>

Description
        Most libc implementations have realloc(p,0) be consistent with
        malloc(0).  If their malloc(0) returns nonnull, realloc(p,0)
        also returns nonnull.  If their malloc(0) returns a null
        pointer, realloc(p,0) also returns a null pointer.

        That consistency was present in the old UNIX V7, where
        realloc(3) was first introduced, and it has been consistent in
        all the descendents of the UNIX system.

        The original malloc(0) in UNIX v7 returned non-null.  UNIX v6
        had alloc(3), which was the precursor of V7's malloc(3), and it
        also returned non-null.  The BSD line kept this behavior, while
        SysV eventually moved to returning a null pointer, in what seems
        a documentation bug that eventually degenerated into the actual
        behavior.

        Regardless of the result of malloc(0) in the descendents of the
        UNIX system, they all maintained a congruency between malloc(0)
        and realloc(p,0).

        Until the ISO C and POSIX standards were badly written, and also
        badly rewritten, and they allowed behaviors that didn't make any
        sense, and which didn't derive from any existing implementation.

        Then, glibc was written by following the letter of the standard,
        instead of trying to follow what other systems do.  And this
        resulted in a self-inconsistent implementation, whose malloc(0)
        returns non-null, but whose realloc(p,0) returns a null pointer.

        Bionic libc followed glibc, and has the same self-inconsistent
        behavior.

        There are no other known libc implementations whose realloc(p,0)
        isn't consistent with malloc(0).  Even musl libc, which coexists
        in Linux systems with glibc, has a realloc(p,0) which is
        consistent with malloc(0) and returns non-null.

        There are glibc maintainers that agree with fixing glibc to be
        self-consistent, but a few of them are worried that the
        C Committee might standardize in a different way, so they are
        reticent to fix their implementation if the C Committee doesn't
        agree on a direction.

        At the same time, the C Committee refuses standardization of
        realloc(p,0) due to existing implementations being inconsistent
        in dangerous ways.

Prior art
        gnulib has a module realloc-posix, whose behavior was like the
        one in glibc.  After realizing how bad this behavior was, gnulib
        has changed to be consistent with malloc(), and thus return
        non-null.  This was done in commit

                gnulib.git d884e6fc4a60 (2024-11-03, 2024-11-04; 
"realloc-posix: realloc (..., 0) now returns nonnull")

        After more than half a year since that, no regressions have been
        reported.  As expected, there was no fallout at all from this
        change.

Questions to the committee
        Does the C Committee agree on a change along the lines of the
        proposed wording in this proposal, conditional to glibc and
        Bionic libc fixing their implementations in this direction
        first?

Future directions
        malloc(0) returning a null pointer on success originated as a
        documentation bug in SysV, and later became the actual behavior.
        It was standardized in C89 maybe because early SVID
        specifications documented that, or maybe simply because C89 had
        this idea that 0-sized objects cannot exist.  Regardless of the
        rationale, it results in malloc(0) being hard to use correctly
        on those systems.  Fixing malloc(0) to return non-null would
        result in many bugs fixed, and probably no regressions.  I plan
        to propose mandating malloc(0) to return non-null, as any other
        malloc() call.

        realloc(p,0) will then also return non-null, as the wording
        below defines it as if it called malloc().

Proposed wording
        Based on N3550.

    7.25.4.8  Memory management functions :: The realloc function
        @@ Description
        +On success,
        +the realloc function
         behaves like <tt>free(ptr); malloc(size)</tt>.
         deallocates the old object pointed to by ptr
        +as if by a call to <b>free</b>,
         and returns a pointer to a new object
        -that has the size specified by size.
        -that has the size specified by size
        +as if by a call to <b>malloc</b>.
         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 unspecified values.

        ## The following sentence seems redundant with the specification
        ## above.
        -If ptr is a null pointer,
        -the realloc function behaves
        -like the malloc function for the specified size.
        -Otherwise,
        -if <tt>ptr</tt> does not match
        +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 free or realloc function,
        -or if the size is zero,
         the behavior is undefined.
        -If memory for the new object is not allocated,
        +If allocation of the new object fails,
         the old object is not deallocated and its value is unchanged.

-- 
<https://www.alejandro-colomar.es/>

Attachment: signature.asc
Description: PGP signature

Reply via email to