mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found] <qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv>
@ 2025-06-16 16:40 ` enh
  2025-06-16 21:21   ` Alejandro Colomar
  2025-06-16 18:20 ` Adhemerval Zanella Netto
  2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
  2 siblings, 1 reply; 38+ messages in thread
From: enh @ 2025-06-16 16:40 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: libc-alpha, наб,
	Paul Eggert, Robert Seacord, musl, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

On Mon, Jun 16, 2025 at 7:55 AM Alejandro Colomar <alx@kernel.org> wrote:
>
> Hi!
>
> For context, the old discussion was in this thread:
> <https://inbox.sourceware.org/libc-alpha/nbyurzcgzgd5rdybbi4no2kw5grrc32k63svf7oq73nfcbus5r@77gry66kpqfr/>
>
> Also for context, here's the excellent research by наб about malloc(0)
> and realloc(p, 0) in historic UNIX systems and their descendents:
> <https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
>
> We discussed last year about realloc(p, 0) being problematic currently
> in glibc.  Ideally, realloc(p, n) should be consistent with malloc(n)
> in that:
>
> -  It is equivalent to free(p) and malloc(n), regardless of the value of
>    n, including when it is 0, and regardless of p, including when it is
>    NULL.

android has these tests in the compatibility test suite (cts):

TEST(malloc, realloc_nullptr_0) {
  // realloc(nullptr, size) is actually malloc(size).
  void* p = realloc(nullptr, 0);
  ASSERT_TRUE(p != nullptr);
  free(p);
}

TEST(malloc, realloc_0) {
  void* p = malloc(1024);
  ASSERT_TRUE(p != nullptr);
  // realloc(p, 0) is actually free(p).
  void* p2 = realloc(p, 0);
  ASSERT_TRUE(p2 == nullptr);
}

> -  Except that of course, if there's enough contiguous space, it doesn't
>    free/malloc, and taht if malloc(n) fails, it doesn't free(p).
>
> This congruency existed in every UNIX system and their descendents,
> including the historic BSDs.  It wasn't until new systems were written
> artificially by the letter of the standard, without regards to
> self-consistency, when this congruency was broken.  I believe glibc was
> the first one to do that, and I don't know/remember if any other systems
> followed glibc.
>
> Paul Eggert and I are convinced that changing the implementation to
> conform to this behavior consistent with malloc(0) would be harmless.
> As such, we modified gnulib's realloc-posix module to conform to that.
> This was done in
>
>         d884e6fc4a60 (2024-11-03, 2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
>
> After more than half a year of changing the behavior in gnulib, there
> have been no dramatic consequences.  As expected, no fallout at all.
>
> Now, can we please make the same change in glibc?
>
> I've CCed musl and Elliott (Bionic), because I don't remember what's the
> behavior in their libraries.  Is it already self-consistent in musl and
> Bionic?  Or do they need a similar fix?
>
> glibc (and possibly libraries that attempt glibc compatibility) is the
> only libc implementation that is not self consistent, and by which ISO C
> has UB in realloc(p, 0).  We expect that when glibc is fixed,
> realloc(p, 0) can be allowed again in ISO C, and can be specified to be
> consistent with malloc(0), thus removing a case of UB.
>
>
> Have a lovely day!
> Alex
>
> --
> <https://www.alejandro-colomar.es/>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found] <qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv>
  2025-06-16 16:40 ` [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0) enh
@ 2025-06-16 18:20 ` Adhemerval Zanella Netto
       [not found]   ` <87y0trv5sq.fsf@oldenburg.str.redhat.com>
  2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
  2 siblings, 1 reply; 38+ messages in thread
From: Adhemerval Zanella Netto @ 2025-06-16 18:20 UTC (permalink / raw)
  To: musl, Alejandro Colomar, libc-alpha, Joseph Myers
  Cc: наб,
	Paul Eggert, Robert Seacord, Elliott Hughes, Bruno Haible,
	bug-gnulib, JeanHeyd Meneide



On 16/06/25 08:55, Alejandro Colomar wrote:
> Hi!
> 
> For context, the old discussion was in this thread:
> <https://inbox.sourceware.org/libc-alpha/nbyurzcgzgd5rdybbi4no2kw5grrc32k63svf7oq73nfcbus5r@77gry66kpqfr/>
> 
> Also for context, here's the excellent research by наб about malloc(0)
> and realloc(p, 0) in historic UNIX systems and their descendents:
> <https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
> 
> We discussed last year about realloc(p, 0) being problematic currently
> in glibc.  Ideally, realloc(p, n) should be consistent with malloc(n)
> in that:
> 
> -  It is equivalent to free(p) and malloc(n), regardless of the value of
>    n, including when it is 0, and regardless of p, including when it is
>    NULL.
> 
> -  Except that of course, if there's enough contiguous space, it doesn't
>    free/malloc, and taht if malloc(n) fails, it doesn't free(p).
> 
> This congruency existed in every UNIX system and their descendents,
> including the historic BSDs.  It wasn't until new systems were written
> artificially by the letter of the standard, without regards to
> self-consistency, when this congruency was broken.  I believe glibc was
> the first one to do that, and I don't know/remember if any other systems
> followed glibc.
> 
> Paul Eggert and I are convinced that changing the implementation to
> conform to this behavior consistent with malloc(0) would be harmless.
> As such, we modified gnulib's realloc-posix module to conform to that.
> This was done in
> 
> 	d884e6fc4a60 (2024-11-03, 2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
> 
> After more than half a year of changing the behavior in gnulib, there
> have been no dramatic consequences.  As expected, no fallout at all.
> 
> Now, can we please make the same change in glibc?
> 
> I've CCed musl and Elliott (Bionic), because I don't remember what's the
> behavior in their libraries.  Is it already self-consistent in musl and
> Bionic?  Or do they need a similar fix?
> 
> glibc (and possibly libraries that attempt glibc compatibility) is the
> only libc implementation that is not self consistent, and by which ISO C
> has UB in realloc(p, 0).  We expect that when glibc is fixed,
> realloc(p, 0) can be allowed again in ISO C, and can be specified to be
> consistent with malloc(0), thus removing a case of UB.
I have re-read the whole thread and it seems that most maintainers are OK
with this change and agree that current POSIX's realloc spec has some 
drawbacks (albeit it still allows current glic behavior).

The only one involved in the previous thread that raised some objection to
this change was Joseph [1], but I will let to say if he still think this
potential change to glibc is ill-advised.

So what I would expect to move this forwards will be to.

1. Reopen https://sourceware.org/bugzilla/show_bug.cgi?id=12547

2. Follow the suggestions laid out by Siddhesh [2].  The Distribution-wide
   verification seems already to be in progress, with some good results
   from gnulib realloc replacement and some work by you on checking some
   other projects (systemd for instance).

3. Prepare the patch to change it, along with the manual documentation,
   regression testcase, and the NEW entry.

4. Since we are near to 2.42 release, this change should be done once 
   2.43 starts to give some time to check potential issue with rolling 
   distros like Fedora Rawhide.

What I do *not* think it would be worthwhile is adding either a compile
or runtime (through tunables) to reinstate old behaviour; this is really
adds some maintainability burden to what seems to be bad behavior that
eventually will be removed from standards. I am not sure about a 
compatibility symbol.

[1] https://inbox.sourceware.org/libc-alpha/ece1e7ef-ad40-e5cd-9aa4-438854fe443e@redhat.com/
[2] https://inbox.sourceware.org/libc-alpha/a69a4a81-208e-4d8c-8201-05f657e9fe4c@gotplt.org/

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]   ` <87y0trv5sq.fsf@oldenburg.str.redhat.com>
@ 2025-06-16 20:59     ` Adhemerval Zanella Netto
  2025-06-16 21:44     ` Alejandro Colomar
  1 sibling, 0 replies; 38+ messages in thread
From: Adhemerval Zanella Netto @ 2025-06-16 20:59 UTC (permalink / raw)
  To: Florian Weimer
  Cc: musl, Alejandro Colomar, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Elliott Hughes, Bruno Haible,
	bug-gnulib, JeanHeyd Meneide



On 16/06/25 16:35, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
> 
>> I have re-read the whole thread and it seems that most maintainers are OK
>> with this change and agree that current POSIX's realloc spec has some 
>> drawbacks (albeit it still allows current glic behavior).
>>
>> The only one involved in the previous thread that raised some objection to
>> this change was Joseph [1], but I will let to say if he still think this
>> potential change to glibc is ill-advised.
> 
> I objected then, and I'm objecting now as well.
> 
> My rationale has not changed:
> 
> <https://inbox.sourceware.org/libc-alpha/8734kl1pim.fsf@oldenburg.str.redhat.com/>
> 
> I believe Siddhesh's proposed patch as the time was mostly a device to
> drive the discussion to a conclusion, which it did.

Alright, sorry if I missed it (for some reason Alejandro link did not have
your reply in the thread overview).

So I think we are far from consensus on this change.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
  2025-06-16 16:40 ` [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0) enh
@ 2025-06-16 21:21   ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-16 21:21 UTC (permalink / raw)
  To: enh
  Cc: libc-alpha, наб,
	Paul Eggert, Robert Seacord, musl, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 1747 bytes --]

Hi Elliott,

On Mon, Jun 16, 2025 at 12:40:18PM -0400, enh wrote:
> On Mon, Jun 16, 2025 at 7:55 AM Alejandro Colomar <alx@kernel.org> wrote:
> >
> > Hi!
> >
> > For context, the old discussion was in this thread:
> > <https://inbox.sourceware.org/libc-alpha/nbyurzcgzgd5rdybbi4no2kw5grrc32k63svf7oq73nfcbus5r@77gry66kpqfr/>
> >
> > Also for context, here's the excellent research by наб about malloc(0)
> > and realloc(p, 0) in historic UNIX systems and their descendents:
> > <https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
> >
> > We discussed last year about realloc(p, 0) being problematic currently
> > in glibc.  Ideally, realloc(p, n) should be consistent with malloc(n)
> > in that:
> >
> > -  It is equivalent to free(p) and malloc(n), regardless of the value of
> >    n, including when it is 0, and regardless of p, including when it is
> >    NULL.
> 
> android has these tests in the compatibility test suite (cts):
> 
> TEST(malloc, realloc_nullptr_0) {
>   // realloc(nullptr, size) is actually malloc(size).
>   void* p = realloc(nullptr, 0);
>   ASSERT_TRUE(p != nullptr);
>   free(p);
> }
> 
> TEST(malloc, realloc_0) {
>   void* p = malloc(1024);
>   ASSERT_TRUE(p != nullptr);
>   // realloc(p, 0) is actually free(p).
>   void* p2 = realloc(p, 0);
>   ASSERT_TRUE(p2 == nullptr);
> }

Hmmm, then Bionic is broken, like glibc.  The first test above is good,
but the second is not.  realloc(p, 0) should be free(p) and malloc(0).

That's what we changed in gnulib last year.  I suggest that you apply
the same fix.  If you need convincing, I can try writing a summary of
the old thread.


Have a lovely night!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]   ` <87y0trv5sq.fsf@oldenburg.str.redhat.com>
  2025-06-16 20:59     ` Adhemerval Zanella Netto
@ 2025-06-16 21:44     ` Alejandro Colomar
       [not found]       ` <CAJgzZooXcPUVJ7Z3Nae-2WRsjpFnNVZpGU0aJyysM2Mv89PSgg@mail.gmail.com>
  1 sibling, 1 reply; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-16 21:44 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Elliott Hughes, Bruno Haible,
	bug-gnulib, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 4419 bytes --]

Hi Florian,

On Mon, Jun 16, 2025 at 09:35:01PM +0200, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
> 
> > I have re-read the whole thread and it seems that most maintainers are OK
> > with this change and agree that current POSIX's realloc spec has some 
> > drawbacks (albeit it still allows current glic behavior).
> >
> > The only one involved in the previous thread that raised some objection to
> > this change was Joseph [1], but I will let to say if he still think this
> > potential change to glibc is ill-advised.
> 
> I objected then, and I'm objecting now as well.
> 
> My rationale has not changed:
> 
> <https://inbox.sourceware.org/libc-alpha/8734kl1pim.fsf@oldenburg.str.redhat.com/>
> 
> I believe Siddhesh's proposed patch as the time was mostly a device to
> drive the discussion to a conclusion, which it did.

I'll quote your rationale from the link:

| * Siddhesh Poyarekar:
| | Nope, please read the threads carefully; I actually said that I won't
| | sustain an objection if I'm the only one holding that opinion.
| 
| I'm still objecting, I don't think this change is valuable.
| 
| I'm open to looking at this again once the C standard fully specifies
| the behavior of zero-sized objects, the return value of malloc (0), and
| so on.

I'm working on that.  I have a proposal for mandating that malloc(0),
but I can't present it until realloc(p, 0) is fixed.  And the
C Committee has refused to fix realloc(p, 0) by decree, so until the
remaining implementations that are broken fix their implementations, we
can't think of having the standard fixed.

Since glibc and Bionic are the two implementations that are currently
broken, could you please fix your implementations?  I'm sure the
C Committee will be much easier to convince if the implentations have
changed in a clear direction.

But if the committee says we're not fixing ISO C until the
implementations are fixed, and the implementations (you) refuse to
accept the fix until the committee standardizes something, then we'll
have the problem forever.

Also, I want to propose 0-length arrays when the arrays are parameters
to functions:

	char *stpecpy(char *dst, char end[0], const char *restrict src);

But again, I can't present this proposal until another one that makes
[n] more meaningful than it is now is merged.  Martin Uecker presented
that one, and I'm waiting for him to sent a revision of his proposal.

So, I'm working in various fronts on having 0-length arrays in the
standard, but there are dependencies before I can propose them.

| Getting aligned behavior between implementations on these
| fundamental interfaces seems quite valuable to programmers.

glibc and Bionic are the only implementations in which realloc(p,0) is
different from free(p) malloc(0).  Fixing glibc (and assuming Bionic
agrees and follows) will solve the problem.

|  But
| addressing one zero-object-size case and leaving all the others as
| unclear as before doesn't seem to be useful,

I have plans to address the other 0-size objects.  Give me time.

| especially given that a
| ffuture standard may require different behavior anyway.

The C Committee seems in favour of removing the UB from realloc(p,0) if
the implementations are fixed first.  Now it's your turn to move.

I'm sure I can convince the committee to follow existing practice.

But I can go a step further:

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?

|  A
| piece-by-piece transition to the newly required behaviors is also more
| onerous on programmers than one well-defined transition in a single
| glibc release.

The realloc(p, 0) is not onerous on programmers at all.  See how the
gnulib went smoothly.  Or do you mean on the implementors?


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re[2]: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]             ` <20250617165644.GY1827@brightrain.aerifal.cx>
@ 2025-06-17 17:38               ` Laurent Bercot
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Bercot @ 2025-06-17 17:38 UTC (permalink / raw)
  To: musl, enh
  Cc: Alejandro Colomar, Florian Weimer, Adhemerval Zanella Netto,
	musl, libc-alpha, Joseph Myers, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

>And folks who do
>know aren't complaining that it's broken, because the behavior is
>currently conforming just bad. Rather they're tiptoeing around the
>issue by special-casing zero and making sure they never pass zero to
>realloc, or wrapping it to do that, etc.

  Anecdotal data point: it's exactly what I do, wrapping all the malloc
and realloc calls so that they're never passed 0. It's by far the
simplest solution for now, at the occasional cost of 1 byte of memory.
It would be nice to have this fixed, *and standardized*; the workarounds
aren't going away until it is, and until every libc deployed under the
sun implements the new, better standard. I'm not holding my breath.

--
  Laurent


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]           ` <CAJgzZoqfDpmig=oCJyrZC9=w1DLnDOeqMk_A5LgJ689_6pZr2g@mail.gmail.com>
       [not found]             ` <20250617165644.GY1827@brightrain.aerifal.cx>
@ 2025-06-17 21:58             ` Alejandro Colomar
       [not found]               ` <mvmmsa56opb.fsf@suse.de>
       [not found]               ` <CAJgzZopU2xDpuYkbJ-W9rURTCFL0tQEYrXKYu7rmkG+UVZzVKw@mail.gmail.com>
  1 sibling, 2 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-17 21:58 UTC (permalink / raw)
  To: enh, Florian Weimer
  Cc: Rich Felker, Adhemerval Zanella Netto, musl, libc-alpha,
	Joseph Myers, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 6487 bytes --]

Hi Elliott, Florian,

glibc and Bionic are non-conforming to POSIX.1-2024.  The fix that we're
proposing would make them conforming.  Does conformance to POSIX.1-2024
mean something to you?

RETURN VALUE

        If size is 0,
        ...
        either:

            -  A null pointer shall be returned
               and, if ptr is not a null pointer,
               errno shall be set to EINVAL.

            -  A pointer to the allocated space shall be returned,
               and the memory object pointed to by ptr shall be freed.
                ...


Please also reply to the message about my proposal for the C Committee.

And Elliott, thanks for noticing that Windows is also crap.  That's
another one to add to the list.


Have a lovely day!
Alex

On Tue, Jun 17, 2025 at 12:13:03PM -0400, enh wrote:
> On Tue, Jun 17, 2025 at 10:51 AM Rich Felker <dalias@libc.org> wrote:
> >
> > On Tue, Jun 17, 2025 at 10:07:07AM -0400, enh wrote:
> > > On Mon, Jun 16, 2025 at 5:44 PM Alejandro Colomar <alx@kernel.org> wrote:
> > > >
> > > > Hi Florian,
> > > >
> > > > On Mon, Jun 16, 2025 at 09:35:01PM +0200, Florian Weimer wrote:
> > > > > * Adhemerval Zanella Netto:
> > > > >
> > > > > > I have re-read the whole thread and it seems that most maintainers are OK
> > > > > > with this change and agree that current POSIX's realloc spec has some
> > > > > > drawbacks (albeit it still allows current glic behavior).
> > > > > >
> > > > > > The only one involved in the previous thread that raised some objection to
> > > > > > this change was Joseph [1], but I will let to say if he still think this
> > > > > > potential change to glibc is ill-advised.
> > > > >
> > > > > I objected then, and I'm objecting now as well.
> > > > >
> > > > > My rationale has not changed:
> > > > >
> > > > > <https://inbox.sourceware.org/libc-alpha/8734kl1pim.fsf@oldenburg.str.redhat.com/>
> > > > >
> > > > > I believe Siddhesh's proposed patch as the time was mostly a device to
> > > > > drive the discussion to a conclusion, which it did.
> > > >
> > > > I'll quote your rationale from the link:
> > > >
> > > > | * Siddhesh Poyarekar:
> > > > | | Nope, please read the threads carefully; I actually said that I won't
> > > > | | sustain an objection if I'm the only one holding that opinion.
> > > > |
> > > > | I'm still objecting, I don't think this change is valuable.
> > > > |
> > > > | I'm open to looking at this again once the C standard fully specifies
> > > > | the behavior of zero-sized objects, the return value of malloc (0), and
> > > > | so on.
> > > >
> > > > I'm working on that.  I have a proposal for mandating that malloc(0),
> > > > but I can't present it until realloc(p, 0) is fixed.  And the
> > > > C Committee has refused to fix realloc(p, 0) by decree, so until the
> > > > remaining implementations that are broken fix their implementations, we
> > > > can't think of having the standard fixed.
> > > >
> > > > Since glibc and Bionic are the two implementations that are currently
> > > > broken, could you please fix your implementations?  I'm sure the
> > > > C Committee will be much easier to convince if the implentations have
> > > > changed in a clear direction.
> > > >
> > > > But if the committee says we're not fixing ISO C until the
> > > > implementations are fixed, and the implementations (you) refuse to
> > > > accept the fix until the committee standardizes something, then we'll
> > > > have the problem forever.
> > >
> > > is it really a problem though? you're basically asking to _add_ an
> > > incompatibility with existing versions of glibc/bionic (so, you know,
> > > "basically every non-Windows computer out there").
> > >
> > > from my perspective:
> > >
> > > pros:
> > > + code would then behave the same on android and ios
> > > cons:
> > > - code would behave differently on different versions of android
> > > - code would behave differently on the host
> > > unknowns:
> > > ? what does Windows do?
> > > ? does anyone actually care?
> > >
> > > not having heard anyone but you bring this up in the last 15 years
> > > (despite it apparently being an android/ios difference), i'm inclined
> > > to assume this is a non-problem that's not worth the disruption of
> > > changing anything...
> >
> > I'm not sure what you mean by "not having heard anyone but you bring
> > this up in the last 15 years". This has been a recurring issue on the
> > glibc bug tracker and in C and POSIX committees, and comes up all the
> > time with users of the language not understanding what the standard
> > says or if/how implementations are conforming. There have been
> > multiple bug reports against different versions of the wording in
> > different versions of the C and POSIX standards, and it's a perpetual
> > source of disagreements.
> 
> yeah, i should probably have said that in my weighting, arguments over
> standards count for nothing compared to existing practice, and only
> "i'm a developer who had a real problem because of this" warrants a
> behavior change. (with my biggest quandary is actually cases exactly
> like this where ios -- which most app developers care about
> compatibility with -- and glibc -- which linux tool developers care
> about -- disagree. as for Windows, that mostly comes up in relation to
> game developers.)
> 
> but, yeah, in 15 years of having both groups complain at me, i've yet
> to see or hear about a single "my code works on ios but not on
> android" bug from this, and obviously we're the same as glibc so
> there's been nothing there.
> 
> > Indeed fixing the bug will not make any immediate improvement. For
> > decades applications will still need to assume they might be running
> > on a system with the broken (inconsistent) behavior like glibc or
> > Bionic, or apply a wrapper to fix it (ala gnulib). But maybe
> > eventually that can become a bad chapter of history we leave behind.
> >
> > One thing I kinda would like to think about is if there's a way we can
> > signal at compile-time (without run tests that don't work for cross
> > compiling) that realloc is non-broken and doesn't need gnulib-style
> > wrapping/replacement. My hope is that such a mechanism would follow
> > the principles of the "Macro-based advertisement of libc extensions"
> > proposal on libc-coord.
> >
> > Rich

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]               ` <mvmmsa56opb.fsf@suse.de>
@ 2025-06-18 18:05                 ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-18 18:05 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: enh, Florian Weimer, musl, Rich Felker, Adhemerval Zanella Netto,
	libc-alpha, Joseph Myers, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 852 bytes --]

Hi Andreas,

On Wed, Jun 18, 2025 at 05:42:40PM +0200, Andreas Schwab wrote:
> On Jun 17 2025, Alejandro Colomar wrote:
> 
> > RETURN VALUE
> >
> >         If size is 0,
> >         ...
> >         either:
> >
> >             -  A null pointer shall be returned
> >                and, if ptr is not a null pointer,
> >                errno shall be set to EINVAL.
> >
> >             -  A pointer to the allocated space shall be returned,
> >                and the memory object pointed to by ptr shall be freed.
> >                 ...
> >
> 
> Note that all of this is marked obsolescent.

Note that it's marked obsolescent because ISO C has turned this into UB.
If ISO C defines the behavior again, then the obsolescence of this could
be reverted.


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                 ` <20250618163550.GZ1827@brightrain.aerifal.cx>
@ 2025-06-18 19:04                   ` Alejandro Colomar
       [not found]                     ` <4b5wiz62y5pq5hiepuqwjt7gmfbu2lnz5nalxrocl2yzxowdx7@m6sus2kdvepw>
  0 siblings, 1 reply; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-18 19:04 UTC (permalink / raw)
  To: Rich Felker
  Cc: enh, Florian Weimer, Adhemerval Zanella Netto, musl, libc-alpha,
	Joseph Myers, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

[-- Attachment #1: Type: text/plain, Size: 3598 bytes --]

Hi Rich, Elliott,

On Wed, Jun 18, 2025 at 12:35:50PM -0400, Rich Felker wrote:
> On Wed, Jun 18, 2025 at 11:20:54AM -0400, enh wrote:
> > On Tue, Jun 17, 2025 at 5:58 PM Alejandro Colomar <alx@kernel.org> wrote:
> > >
> > > Hi Elliott, Florian,
> > >
> > > glibc and Bionic are non-conforming to POSIX.1-2024.  The fix that we're
> > > proposing would make them conforming.  Does conformance to POSIX.1-2024
> > > mean something to you?
> > 
> > not when POSIX screwed up and made a change that made most of the
> > existing implementations non-conformant, no. that sounds like a POSIX
> > bug to me...

Not most.  Only two POSIX implementations, plus Windows.  And the
solution is easy: fix the implementations.  There have been no
regression reports in gnulib since we fixed it last year.

> > (like i said, i care greatly about actual shipping code. a standard is
> > interesting for green-field stuff, but when it's at odds with reality
> > it's often worse to try to adapt than just ignore the stupidity/report
> > the bug and get it changed back.)

It's ironic that the standard should have never said that, because prior
to the existence of ANSI C and POSIX, all existing systems behaved like
the current POSIX specification.  It was a consequence of the horrible
wording of the standards, that glibc was written so badly, by following
a bogus specification, when it should have been made compatible with the
existing systems.

Thus, this is a historical bug in ISO C, POSIX, which at least has been
finally fixed in POSIX.

BTW, the same text is present in POSIX.1-2017.  It was changed in a TC,
following bug <https://www.austingroupbugs.net/view.php?id=400>.

The motivation, from what I can read there, seems to be that C99 already
made POSIX.1 non-conforming, and this fix was intended to conform to
C99.

Indeed, glibc is non-conforming to C99 too.  Although, I don't like the
wording from C99, either; it allows weird stuff: it allows an
implementation where malloc(0) returns NULL and realloc(p,0) non-null
(so, the opposite of glibc).

C11 is essentially identical to C99 in that regard, so glibc is also
non-conforming to C11.

C17 changed to something very weird.  It seems to me that glibc is
conforming again to C17, but it also seems to me that it's impossible to
write code that uses realloc(p,0) in a portable way with this
specification.  I think it's a good thing that C23 removed that crap.


Here's a summary of conformance to standards:

	glibc conforms to:
		-  SysVr4
		-  ISO C89
		-  ISO C17
		-  XPG4

	glibc doesn't conform to:
		-  SysIII
		-  SysV
		-  SysVr2
		-  SysVr3
		-  SVID Issue 2
		-  SVID Issue 3
		-  The X/Open System V Specification
		-  ISO C99
		-  ISO C11
		-  POSIX.1-2001
		-  POSIX.1-2008
		-  POSIX.1-2017
		-  POSIX.1-2024

Conformance to POSIX.1-2001 and POSIX.1-2008 is not clear.  While glibc
conforms to the wording of these standards, these standards have the
following header in the realloc(3) specification:

	The functionality described on this reference page is aligned
	with the ISO C standard.  Any conflict between the requirements
	described here and the ISO C standard is unintentional.  This
	volume of IEEE Std 1003.1-2001 defers to the ISO C standard.

Which means that POSIX's permissive wording is unintentional, and the
ISO C99 wording is the one that matters, so glibc is non-conforming.

(I didn't mention C23, since it's UB, so anything conforms.)


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                       ` <2sqn2ggwgtgjhrd7p57ipbxqe7ncpk3c5rmyvvqlumvyecsk5q@ufffzvlrnvpk>
@ 2025-06-20  2:11                         ` Vincent Lefevre
       [not found]                           ` <l47kg74zm6wukxn7hm3lot73bt5huhtal32fhpj25aozfncuw7@qgf5o3m5do5o>
  2025-06-20 13:42                         ` Mark Harris
                                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 38+ messages in thread
From: Vincent Lefevre @ 2025-06-20  2:11 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

On 2025-06-20 01:37:58 +0200, Alejandro Colomar wrote:
> On Thu, Jun 19, 2025 at 01:31:06PM -0500, Eric Blake wrote:
> > On Wed, Jun 18, 2025 at 09:04:02PM +0200, Alejandro Colomar wrote:
> > > 	glibc doesn't conform to:
> > > 		-  SysIII
> > > 		-  SysV
> > > 		-  SysVr2
> > > 		-  SysVr3
> > > 		-  SVID Issue 2
> > > 		-  SVID Issue 3
> > > 		-  The X/Open System V Specification
> > > 		-  ISO C99
> > 
> > Here, section 7.20.3.4 is relevant. In there, I see wording "If ptr is
> > a null pointer, the realloc function behaves like the malloc function
> > for the specified size." but NO wording about when ptr is non-null but
> > size is 0.  As best I can tell, silence on the part of C99 means that
> > the standard is unspecified, and therefore glibc can do whatever it
> > wants and still claim compliance.  But I'm open to correction if you
> > can quote the exact statement for why you claim glibc is non-compliant
> > here.
> 
> <https://port70.net/~nsz/c/c99/n1256.html#7.20.3.4>
> 
> I'll quote the entire text:
> 
> 	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.
> 		[...]  // talks about the contents
> 
> 	3	If ptr is a null pointer, [...].
> 		Otherwise,
> 		if ptr does not match a pointer earlier returned by
> 		the calloc, malloc, [...], 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. 
> 
> IMO, paragraph 4 rules out the possibility of returning a null pointer
> on success.

Perhaps not if size is 0, see below.

> Also, while it doesn't specify what happens in the case of size 0
> explicitly, it mentions in paragraph 2 what happens for all sizes:
> it returns a pointer to a new object that has the size specified by
> size --which in this case is 0 bytes--.

You should also consider the end of 7.20.3p1 (which applies to calloc,
malloc and realloc):

  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.

Consider the case "a null pointer is returned" with realloc(non_null,0).
I can see 2 possible interpretations:

1. This is always a failure (corresponding to "a null pointer if the
new object could not be allocated" in 7.20.3.4p4). But I doubt that
this is the intended behavior, as there would be major memory leaks
in practice with such an implementation and would make such a call
useless.

2. This means that the memory is entirely freed, which is a success.
This makes your assumption "paragraph 4 rules out the possibility of
returning a null pointer on success" above wrong. However, in order
to know whether a null pointer means a success (memory entirely freed)
or a failure (for the case "the behavior is as if the size were some
nonzero value"), the application would need to know which kind of
implementation it is (e.g. guessed by tools like configure tests).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                       ` <1804ec5c-d024-448e-beb2-f682384c70d4@cs.ucla.edu>
@ 2025-06-20 10:04                         ` Vincent Lefevre
  0 siblings, 0 replies; 38+ messages in thread
From: Vincent Lefevre @ 2025-06-20 10:04 UTC (permalink / raw)
  To: Paul Eggert
  Cc: Eric Blake, Alejandro Colomar, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Robert Seacord, Bruno Haible, bug-gnulib, JeanHeyd Meneide,
	Thorsten Glaser

On 2025-06-19 22:55:32 -0700, Paul Eggert wrote:
> Thanks for the detailed summary. Here are a few more details. In this
> summary "realloc(p,0)" assumes p is nonnull.
> 
> As I understand it:
> 
> (a) These guarantees are for compatibility with glibc 2.2+. In older glibc
> versions realloc(p,0) behaved like (free(p),malloc(0)).
> 
> (b) Ulrich Drepper changed glibc 2.2 realloc(p,0) after Andreas Jaeger told
> him[1] that draft C99 and UNIX98 required realloc(p,0) to free(p).
> Conformance to these standards was the only motivation given for the glibc
> change.

BTW, at that time, the lack of consistency between realloc(...,0)
and malloc(0) was known and not regarded as an issue:

  https://sourceware.org/pipermail/libc-alpha/1999-April/002398.html

> (c) Ulrich's change[2] to glibc was to make realloc(p,0) equivalent to
> (free(p),0). Draft C99 and UNIX98 did not require this, and Ulrich could
> have made realloc(p,0) continue to be equivalent to (free(p),malloc(0)).
[...]

Indeed, at least the N843 C9x draft (August 1998) did not require this.
It had new text, saying:

  If the realloc function returns a null pointer when size is zero and
  ptr is not a null pointer, the object it pointed to has been freed.

There are also some changes for realloc proposed in

  https://www.open-std.org/jtc1/sc22/wg14/www/docs/n868.htm

(Final CD Ballot for FCD 9899), but nothing for the case of size = 0.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                       ` <2sqn2ggwgtgjhrd7p57ipbxqe7ncpk3c5rmyvvqlumvyecsk5q@ufffzvlrnvpk>
  2025-06-20  2:11                         ` Vincent Lefevre
@ 2025-06-20 13:42                         ` Mark Harris
  2025-06-20 16:18                           ` Joseph Myers
  2025-06-21  3:57                         ` Sam James
       [not found]                         ` <ymigejkdbyrxohd5chrigpfvztnia2nw4u3jmdiw6vke2xs3me@xb5t6hevzuba>
  3 siblings, 1 reply; 38+ messages in thread
From: Mark Harris @ 2025-06-20 13:42 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

Alejandro Colomar wrote:
> I don't have a copy of POSIX.1-1988, nor of any other POSIX.1 before
> POSIX.1-2001.  What do they say for realloc(3)?

The first POSIX edition with a description of realloc is POSIX.1-2001.
Earlier editions only list it as a function provided by the C Language
Standard.

POSIX.1-1988 Appendix A states:
"This IEEE Std 1003.1-1988 is intended to complement others that
together would provide a comprehensive Open System Environment."
...
"This document refers to the C Language Standard effort presently
under development by Technical Committee X3J11 of the Accredited
Standards Committee X3—Information Processing Systems. The X3J11 and
1003.1 groups have been cooperating to ensure that the standards are
complementary and not overlapping."

There were three editions of POSIX prior to POSIX.1-2001:

IEEE Std 1003.1-1988:
https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub151-1.pdf

IEEE Std 1003.1-1990:
https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub151-2.pdf

IEEE Std 1003.1-1996 = 1003.1-1990 + 1003.1b-1993 + 1003.1c-1995 +
1003.1i-1995 (i.e., same as the previous version plus real-time and
threading extensions; no impact on realloc)

>
> I don't have a copy of POSIX.1-2008 ...

https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/realloc.html

> > No mention of POSIX.1-2013?
>
> I didn't have a copy of that.  ...

https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/functions/realloc.html

POSIX.1-2013 = POSIX.1-2008 + TC1;
TC1 includes the POSIX changes to realloc from bug 400.

https://austingroupbugs.net/view.php?id=400
https://open-std.org/JTC1/SC22/WG14/www/docs/dr_400.htm


 - Mark

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                           ` <l47kg74zm6wukxn7hm3lot73bt5huhtal32fhpj25aozfncuw7@qgf5o3m5do5o>
@ 2025-06-20 14:36                             ` Vincent Lefevre
  2025-06-20 14:56                               ` Alejandro Colomar
  0 siblings, 1 reply; 38+ messages in thread
From: Vincent Lefevre @ 2025-06-20 14:36 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

On 2025-06-20 13:58:23 +0200, Alejandro Colomar wrote:
> On Fri, Jun 20, 2025 at 04:11:23AM +0200, Vincent Lefevre wrote:
> > You should also consider the end of 7.20.3p1 (which applies to calloc,
> > malloc and realloc):
> > 
> >   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.
> 
> Right.  I missed that part.
> 
> So, C99 and C11 allow realloc(p,0) to return a null pointer.
> 
> > Consider the case "a null pointer is returned" with realloc(non_null,0).
> > I can see 2 possible interpretations:
> > 
> > 1. This is always a failure (corresponding to "a null pointer if the
> > new object could not be allocated" in 7.20.3.4p4). But I doubt that
> > this is the intended behavior, as there would be major memory leaks
> > in practice with such an implementation and would make such a call
> > useless.
> > 
> > 2. This means that the memory is entirely freed, which is a success.
> > This makes your assumption "paragraph 4 rules out the possibility of
> > returning a null pointer on success" above wrong. However, in order
> > to know whether a null pointer means a success (memory entirely freed)
> > or a failure (for the case "the behavior is as if the size were some
> > nonzero value"), the application would need to know which kind of
> > implementation it is (e.g. guessed by tools like configure tests).
> 
> To disambiguate, we need to read
> 
> <https://port70.net/~nsz/c/c99/n1256.html#7.20.3.4>
> 
> First p4:
> 
> 	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.
> 
> So, a null pointer, which is allowed for r(p,0), means that "the new
> object could not be allocated".
> 
> And then we read the last sentence of p3:
> 
> 	3	[...]
> 		If memory for the new object cannot be allocated,
> 		the old object is not deallocated and its value is unchanged.
> 
> So, the input pointer must not be freed.

Yes, this is what I mentioned in interpretation 1 above (so with
memory leaks in practice, as applications call realloc(non_null,0)
to free memory, while memory will never be freed).

But I believe that this was not the intent of the C Committee.
If it were, the text would have been different, IMHO.

This is too late for a defect report anyway, as the current standard
is C23 and realloc(non_null,0) is now UB. But if one wants to avoid
the UB in a future standard, the above remarks need to be considered.

> I'd say glibc is non-conforming, even if this could possibly have been
> unintended by the C Committee.

Well, strictly speaking, with the UB, it is conforming (at least with
a non-null pointer). I'm not sure that speaking of conformity against
old standards makes sense if there is a suspicion of defect (and in
particular, if this has been resolved by a change in the current
standard, like here).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
  2025-06-20 14:36                             ` Vincent Lefevre
@ 2025-06-20 14:56                               ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-20 14:56 UTC (permalink / raw)
  To: Vincent Lefevre, Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

[-- Attachment #1: Type: text/plain, Size: 1786 bytes --]

Hi Vincent,

On Fri, Jun 20, 2025 at 04:36:31PM +0200, Vincent Lefevre wrote:
> > So, the input pointer must not be freed.
> 
> Yes, this is what I mentioned in interpretation 1 above (so with
> memory leaks in practice, as applications call realloc(non_null,0)
> to free memory, while memory will never be freed).
> 
> But I believe that this was not the intent of the C Committee.
> If it were, the text would have been different, IMHO.
> 
> This is too late for a defect report anyway, as the current standard
> is C23 and realloc(non_null,0) is now UB. But if one wants to avoid
> the UB in a future standard, the above remarks need to be considered.

There's a way forward that would prevent the leaks: force the musl
behavior: free the object, and return a non-null pointer, like
malloc(0).  You'd still leak 0 bytes + metadata in a few rare cases, but
that's not a big deal.

> > I'd say glibc is non-conforming, even if this could possibly have been
> > unintended by the C Committee.
> 
> Well, strictly speaking, with the UB, it is conforming (at least with
> a non-null pointer). I'm not sure that speaking of conformity against
> old standards makes sense if there is a suspicion of defect (and in
> particular, if this has been resolved by a change in the current
> standard, like here).

I think it is important in this case, because if glibc decided to
conform to older standards --and it very well could, just as gnulib
did--, the UB could be reverted, and users could use realloc(p,0) in the
future safely.

Now, the ball is in glibc.  (Or the standard might unilaterally impose
that glibc be fixed, but it would be nicer if glibc would do so
voluntarily.)


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
  2025-06-20 13:42                         ` Mark Harris
@ 2025-06-20 16:18                           ` Joseph Myers
  0 siblings, 0 replies; 38+ messages in thread
From: Joseph Myers @ 2025-06-20 16:18 UTC (permalink / raw)
  To: Mark Harris
  Cc: Alejandro Colomar, Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

On Fri, 20 Jun 2025, Mark Harris wrote:

> There were three editions of POSIX prior to POSIX.1-2001:

Also the Trial-Use 1986 edition.  (Appendix D, Comparison with Related 
Systems, marks realloc with "**", where "Functions marked ** are 
considered to be included in this standard by reference to the C 
Information Bulletin July 1985 or subsequent standard for the C 
programming language.)

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] alx-0029r1 - Restore the traditional realloc(3) specification
       [not found] <qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv>
  2025-06-16 16:40 ` [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0) enh
  2025-06-16 18:20 ` Adhemerval Zanella Netto
@ 2025-06-20 21:26 ` Alejandro Colomar
  2025-06-20 22:31   ` [musl] " Christopher Bazley
                     ` (6 more replies)
  2 siblings, 7 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-20 21:26 UTC (permalink / raw)
  To: libc-alpha
  Cc: bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Thorsten Glaser, Eric Blake,
	Vincent Lefevre, Mark Harris, Collin Funk, Wilco Dijkstra,
	DJ Delorie, Cristian Rodríguez, Siddhesh Poyarekar,
	Sam James, Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil

[-- Attachment #1: Type: text/plain, Size: 13975 bytes --]

Hi!

After the useful discussion with Eric and Paul, I've rewritten a draft
of a proposal I had for realloc(3) for C2y.  Here it is (see below).

I'll present it here before presenting it to the C Committee (although
several members are CCd).

This time, I opted for an all-in-one change that puts us in the end
goal, since some people were concerned that step-by-step might be less
feasible.  Also, the wording is more consistent doing this at once, and
people know what to expect from the begining.


Have a lovely day!
Alex

---
Name
	alx-0029r1 - Restore the traditional realloc(3) specification

Principles
	-  Uphold the character of the language
	-  Keep the language small and simple
	-  Facilitate portability
	-  Avoid ambiguities
	-  Pay attention to performance
	-  Codify existing practice to address evident deficiencies.
	-  Avoid quiet changes
	-  Enable secure programming

Category
	Remove UB.

Author
	Alejandro Colomar <alx@kernel.org>

	Cc: <bug-gnulib@gnu.org>
	Cc: <musl@lists.openwall.com>
	Cc: <libc-alpha@sourceware.org>
	Cc: наб <nabijaczleweli@nabijaczleweli.xyz>
	Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
	Cc: Paul Eggert <eggert@cs.ucla.edu>
	Cc: Robert Seacord <rcseacord@gmail.com>
	Cc: Elliott Hughes <enh@google.com>
	Cc: Bruno Haible <bruno@clisp.org>
	Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
	Cc: Rich Felker <dalias@libc.org>
	Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
	Cc: Joseph Myers <josmyers@redhat.com>
	Cc: Florian Weimer <fweimer@redhat.com>
	Cc: Laurent Bercot <ska-dietlibc@skarnet.org>
	Cc: Andreas Schwab <schwab@suse.de>
	Cc: Thorsten Glaser <tg@mirbsd.de>
	Cc: Eric Blake <eblake@redhat.com>
	Cc: Vincent Lefevre <vincent@vinc17.net>
	Cc: Mark Harris <mark.hsj@gmail.com>
	Cc: Collin Funk <collin.funk1@gmail.com>
	Cc: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
	Cc: DJ Delorie <dj@redhat.com>
	Cc: Cristian Rodríguez <cristian@rodriguez.im>
	Cc: Siddhesh Poyarekar <siddhesh@gotplt.org>
	Cc: Sam James <sam@gentoo.org>
	Cc: Mark Wielaard <mark@klomp.org>
	Cc: "Maciej W. Rozycki" <macro@redhat.com>
	Cc: Martin Uecker <ma.uecker@gmail.com>
	Cc: Christopher Bazley <chris.bazley.wg14@gmail.com>
	Cc: <eskil@obsession.se>

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

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

	r1 (2025-06-20):
	-  Full rewrite after the recent glibc discussion.

See also
	<https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
	<https://sourceware.org/pipermail/libc-alpha/1999-April/000956.html>
	<https://inbox.sourceware.org/libc-alpha/20241019014002.3684656-1-siddhesh@sourceware.org/T/#u>
	<https://inbox.sourceware.org/libc-alpha/qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv/T/#u>
	<https://github.com/bminor/glibc/commit/7c2b945e1fd64e0a5a4dbd6ae6592a7314dcd4b5>
	<https://www.austingroupbugs.net/view.php?id=400>
	<https://www.austingroupbugs.net/view.php?id=526>
	<https://www.austingroupbugs.net/view.php?id=688>
	<https://sourceware.org/bugzilla/show_bug.cgi?id=12547>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n868.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2438.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf>
	<https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/realloc.html>
	<https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/functions/realloc.html>

Description
	Let's start by quoting the author of realloc(3).

	On 2024-10-18 05:30, Douglas McIlroy wrote:
	> The discussion has taken a turn that's astonishing to one who
	> doesn't know the inside details of real compilers.
	>
	> Regardless of the behavior of malloc(0), one expects this
	> theorem to hold:
	>
	>	Given that p = malloc(n) is not NULL,
	>	that 0<=m<=n,
	>	and that malloc(m) could in some circumstance
	>	return a non-null pointer,
	>	then realloc(p,m) will return a non-null pointer.
	>
	> REALLOC_ZERO_BYTES_FREES flies in the face of this rational
	> expectation about dynamic storage allocation.  A diabolical
	> invention.
	>
	> Doug

	The specification of realloc(3) has been problematic since the
	very first standards, even before ISO C.  The wording has
	changed significantly, trying to forcedly permit implementations
	to return a null pointer when the requested size is zero.  This
	originated from the intent of banning zero-sized objects from
	the language in C89, but that never worked well in
	retrospective, as we can see from the fallout.

	None of the specifications have been good, and C23 finally gave
	up and made it undefined behavior.

	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.

	Code written for platforms returning a null can be migrated to
	platforms returning non-null, without significant issues.

	There are two kinds of code that call realloc(p,0).  One
	hard-codes the 0, and is used as a replacement of free(p).  This
	code ignores the return value, since it's unimportant.  This
	code currently produces a leak of 0 bytes plus associated
	metadata on platforms such as musl libc, where it returns a
	non-null pointer.  However, assuming that there are programs
	written with the knowledge that they won't ever be run on such
	platforms, we should take care of that, and make sure they don't
	leak.  A way of accomplishing this would be to recommend
	implementations to issue a diagnostic when realloc(3) is called
	with a hardcoded zero.  This is only an informal recommendation
	made by this proposal, as this is a matter of QoI, and the
	standard shouldn't say anything about it.  This would prevent
	this class of minor leaks.

	Moreover, in glibc, realloc(p,0) may return non-null, in the
	case where p is NULL, so code must already take that into
	account, and thus code that simply takes realloc(p,0) as a
	synonym of free(p) is already leaky, as free(NULL) is a no-op,
	but realloc(NULL,0) allocates 0 bytes.

	The other kind of code is in algorithms that realloc(3) an
	arbitrary size, which might eventually be zero.  This gets more
	complex.

	Here's the code that should be written for AIX or glibc:

		errno = 0;
		new = realloc(old, size);
		if (new == NULL) {
			if (errno == ENOMEM)
				free(old);
			goto fail;
		}
		...
		free(new);

	Failing to check for ENOMEM in these platforms before freeing
	the old pointer would result in a double-free.  If the program
	decides to continue using the old pointer instead of freeing it,
	it would result in a use-after-free.

	In the platforms where realloc(p,0) returns non-null, such as
	the BSDs or musl libc, it is simpler to handle it:

		new = realloc(old, size);
		if (new == NULL) {  // errno is ENOMEM
			free(old);
			goto fail;
		}
		...
		free(new);

	Whenever the result is a null pointer, these platforms are
	reporting an ENOMEM error, and thus it is superfluous to check
	errno there.

	Most code is written in this way, even if run on platforms
	returning a null pointer.  This is because most programmers are
	just unaware of this problem.

	If the realloc(3) specification was changed to require that
	realloc(p,0) returns non-null on success, and that realloc(p,0)
	only fails when out-of-memory, and to require that it sets
	errno to ENOMEM, then code written for AIX or glibc would
	continue working just fine, since the errno check would be
	redundant with the null check.  Simply, the conditional
	(errno == ENOMEM) would always be true when (new == NULL).

	This makes handling of realloc(3) as straightforward as one
	would expect, with only two states: success or error.

	The resulting wording in the standard is also much simpler, as
	it doesn't need to define so many special cases.

	For consistency, all the other allocation functions are updated
	to both return an .

Prior art
    gnulib
	gnulib provides the realloc-posix module, which aims to wrap the
	system realloc(3) and reallocarray(3) functions so that they
	behave in a POSIX-complying manner.

	It previously behaved like glibc.  After I reported that it was
	non-conforming to POSIX, we discussed the best way forward,
	which we agreed was the same direction that this paper is
	proposing now for C2y.  The implementation was changed in

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

	There have been no regression reports since then, as we
	expected.

    Unix V7
	The proposed behavior is the one endorsed by Doug McIlroy, the
	author of the original implementation of realloc(3) in Unix V7,
	and also present in the BSDs.

Design decisions
	This change needs three changes, which can be applied both at
	once, or in two separate steps.

	The first step would make realloc(p,s) be consistent with
	free(p) and malloc(s), including when p is a null pointer, when
	s is zero, and also when both corner cases happen at the same
	time.  This change would already turn the implementations where
	malloc(0) returns non-null into the end goal we have.

	The first step would require changes to (at least) the following
	implementations: glibc, Bionic, Windows.

	The second step would be to require that malloc(0) returns a
	non-null pointer.

	The second step would require changes to (at least) the
	following implementations: AIX.

	The third step would be to require that on error, errno is set
	to ENOMEM.

	This proposal has merged all steps into a single proposal.

	This proposal also needs to add ENOMEM to the standard, since it
	hasn't been standardized yet.

Future directions
	This proposal, by specifying realloc(3) as-if by calling
	free(3) and malloc(3), makes it redundant several mentions of
	realloc(3) next to either free(3) or malloc(3) in the standard.
	We could remove them in this proposal, or clean up that in a
	separate (mostly editorial) proposal.  Let's keep it for a
	future proposal for now.

Caveats
	Code written today should be careful, in case it can run on
	older systems that are not fixed to comply with this stricter
	specification.  Thus, code written today should call realloc(3)
	similar to this:

		realloc(p, n?n:1);

	When all existing implementations are fixed to comply with this
	stricter specification, that workaround can be removed.

Proposed wording
	Based on N3550.

    7.5  Errors <errno.h>
	## Add ENOMEM in p2.

    7.25.4.1  Memory management functions :: General
	@@ p1
	...
	 If the size of the space requested is zero,
	-the behavior is implementation-defined:
	-either
	-a null pointer is returned to indicate the 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.

    7.25.4.2  The aligned_alloc function
	@@ Returns, p3
	 The <b>aligned_alloc</b> function returns
	-either
	-a null pointer
	-or
	-a pointer to the allocated space.
	+a pointer to the allocated space
	+on success.
	+If
	+the space cannot be allocated,
	+a null pointer is returned,
	+and the value of the macro <b>ENOMEM</b>
	+is stored in <b>errno</b>.

    7.25.4.3  The calloc function
	@@ Returns, p3
	 The <b>calloc</b> function returns
	-either
	 a pointer to the allocated space
	+on success.
	-or a null pointer
	-if
	+If
	 the space cannot be allocated
	 or if the product <tt>nmemb * size</tt>
	-would wraparound <b>size_t</b>.
	+would wraparound <b>size_t</b>,
	+a null pointer is returned,
	+and the value of the macro <b>ENOMEM</b>
	+is stored in <b>errno</b>.

    7.25.4.7  The malloc function
	@@ Returns, p3
	 The <b>malloc</b> function returns
	-either
	-a null pointer
	-or
	-a pointer to the allocated space.
	+a pointer to the allocated space
	+on success.
	+If
	+the space cannot be allocated,
	+a null pointer is returned,
	+and the value of the macro <b>ENOMEM</b>
	+is stored in <b>errno</b>.

    7.25.4.8  The realloc function
	@@ Description, p2
	 The <b>realloc</b> function
	 deallocates the old object pointed to by <tt>ptr</tt>
	+as if by a call to <b>free</b>,
	 and returns a pointer to a new object
	-that has the size specified by <tt>size</tt>.
	+that has the size specified by <tt>size</tt>
	+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.

	@@ 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,
	-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.

	@@ Returns, p4
	 The <b>realloc</b> function returns
	 a pointer to the new object
	 (which can have the same value
	-as a pointer to the old object),
	+as a pointer to the old object)
	+on success.
	-or
	+If
	+space cannot be allocated,
	 a null pointer
	+is returned
	+and the value of the macro <b>ENOMEM</b>
	+is stored in <b>errno</b>.

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
  2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
@ 2025-06-20 22:31   ` Christopher Bazley
  2025-06-21  1:59     ` Alejandro Colomar
  2025-06-20 22:58   ` Maciej W. Rozycki
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 38+ messages in thread
From: Christopher Bazley @ 2025-06-20 22:31 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Thorsten Glaser, Eric Blake,
	Vincent Lefevre, Mark Harris, Collin Funk, Wilco Dijkstra,
	DJ Delorie, Cristian Rodríguez, Siddhesh Poyarekar,
	Sam James, Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	eskil

Hi Alex,

On Fri, Jun 20, 2025 at 10:26 PM Alejandro Colomar <alx@kernel.org> wrote:
>         There are two kinds of code that call realloc(p,0).  One
>         hard-codes the 0, and is used as a replacement of free(p).  This
>         code ignores the return value, since it's unimportant.  This
>         code currently produces a leak of 0 bytes plus associated

I have a feeling that I wrote something like this in one of my emails
but I have since realised that the as-if rule allows "deallocates the
old object pointed to by ptr and returns a pointer to a new object
that has the size specified by size" to be a no-op: an implementation
of realloc could return a pointer to the same heap block whenever the
new requested size is less than or equal to the current size.
Effectively the amount of memory leaked would then be bounded only by
the maximum size of the allocation.

>         metadata on platforms such as musl libc, where it returns a
>         non-null pointer.  However, assuming that there are programs
>         written with the knowledge that they won't ever be run on such
>         platforms, we should take care of that, and make sure they don't
>         leak.  A way of accomplishing this would be to recommend
>         implementations to issue a diagnostic when realloc(3) is called
>         with a hardcoded zero.  This is only an informal recommendation
>         made by this proposal, as this is a matter of QoI, and the
>         standard shouldn't say anything about it.  This would prevent
>         this class of minor leaks.
>
>         Moreover, in glibc, realloc(p,0) may return non-null, in the
>         case where p is NULL, so code must already take that into
>         account, and thus code that simply takes realloc(p,0) as a
>         synonym of free(p) is already leaky, as free(NULL) is a no-op,
>         but realloc(NULL,0) allocates 0 bytes.

This behaviour does not sound good, but I think you are assuming
something about the usage of realloc(p,0): might it be called if and
only if p != NULL?

>         The other kind of code is in algorithms that realloc(3) an
>         arbitrary size, which might eventually be zero.  This gets more
>         complex.
>
>         Here's the code that should be written for AIX or glibc:
>
>                 errno = 0;
>                 new = realloc(old, size);
>                 if (new == NULL) {
>                         if (errno == ENOMEM)
>                                 free(old);
>                         goto fail;
>                 }
>                 ...
>                 free(new);
>
>         Failing to check for ENOMEM in these platforms before freeing
>         the old pointer would result in a double-free.  If the program
>         decides to continue using the old pointer instead of freeing it,
>         it would result in a use-after-free.

The above code looks suspect to me anyway because it does 'goto fail'
in a scenario where errno != ENOMEM, which presumably includes errno
== 0, which should not be considered a failure.

Anyway, isn't there a simpler example that illustrates your point
without relying on errno?

What about this:

                 new = realloc(old, size);
                 if (new == NULL) {
                         if (size != 0) {
                                 free(old);
                                 goto fail;
                         }
                 }
                 ...
                 free(new);

If you are absolutely sure that ENOMEM is required for this case then
the argument that such implementations are compliant with the ISO C
standard is weaker than I initially realised.

>         In the platforms where realloc(p,0) returns non-null, such as
>         the BSDs or musl libc, it is simpler to handle it:
>
>                 new = realloc(old, size);
>                 if (new == NULL) {  // errno is ENOMEM
>                         free(old);
>                         goto fail;
>                 }
>                 ...
>                 free(new);
>
>         Whenever the result is a null pointer, these platforms are
>         reporting an ENOMEM error, and thus it is superfluous to check
>         errno there.
>
>         Most code is written in this way, even if run on platforms
>         returning a null pointer.  This is because most programmers are
>         just unaware of this problem.

Also perhaps because ENOMEM isn't part of ISO standard C therefore it
is not necessarily defined. (e.g., it is not defined in the headers
for the Norcroft C compiler for RISC OS.)

It's interesting to think about why ENOMEM might not be part of the
ISO standard. I suspect the reason is that it was not believed to be
necessary for completeness of any of the standard library interfaces.
Your email suggests otherwise.

>         If the realloc(3) specification was changed to require that

"Were", not "was". Sorry for being pedantic.

>         realloc(p,0) returns non-null on success, and that realloc(p,0)
>         only fails when out-of-memory, and to require that it sets
>         errno to ENOMEM, then code written for AIX or glibc would

You can't require that errno be set to a value that does not exist in
the standard. I see you are planning to add it, but I'm not yet
convinced that is necessary.

>         continue working just fine, since the errno check would be
>         redundant with the null check.  Simply, the conditional
>         (errno == ENOMEM) would always be true when (new == NULL).
>
>         This makes handling of realloc(3) as straightforward as one
>         would expect, with only two states: success or error.
>
>         The resulting wording in the standard is also much simpler, as
>         it doesn't need to define so many special cases.
>
>         For consistency, all the other allocation functions are updated
>         to both return an .

Missing text?

> Prior art
>     gnulib
>         gnulib provides the realloc-posix module, which aims to wrap the
>         system realloc(3) and reallocarray(3) functions so that they
>         behave in a POSIX-complying manner.
>
>         It previously behaved like glibc.  After I reported that it was
>         non-conforming to POSIX, we discussed the best way forward,
>         which we agreed was the same direction that this paper is
>         proposing now for C2y.  The implementation was changed in
>
>                 gnulib.git d884e6fc4a60 (2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
>
>         There have been no regression reports since then, as we
>         expected.
>
>     Unix V7
>         The proposed behavior is the one endorsed by Doug McIlroy, the
>         author of the original implementation of realloc(3) in Unix V7,
>         and also present in the BSDs.
>
> Design decisions
>         This change needs three changes, which can be applied both at
>         once, or in two separate steps.
>
>         The first step would make realloc(p,s) be consistent with
>         free(p) and malloc(s), including when p is a null pointer, when
>         s is zero, and also when both corner cases happen at the same
>         time.  This change would already turn the implementations where
>         malloc(0) returns non-null into the end goal we have.
>
>         The first step would require changes to (at least) the following
>         implementations: glibc, Bionic, Windows.
>
>         The second step would be to require that malloc(0) returns a
>         non-null pointer.
>
>         The second step would require changes to (at least) the
>         following implementations: AIX.
>
>         The third step would be to require that on error, errno is set
>         to ENOMEM.
>
>         This proposal has merged all steps into a single proposal.
>
>         This proposal also needs to add ENOMEM to the standard, since it
>         hasn't been standardized yet.

I think this change would be better served by a separate proposal
unless you believe both:
- that ENOMEM serves a special purpose for realloc, and
- that WG14 can only be persuaded to accept ENOMEM on account of that
special purpose.

I have doubts about both points.

> Future directions
>         This proposal, by specifying realloc(3) as-if by calling
>         free(3) and malloc(3), makes it redundant several mentions of

Extra 'it'.

Overall, I wholeheartedly support your direction.

Chris

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
  2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
  2025-06-20 22:31   ` [musl] " Christopher Bazley
@ 2025-06-20 22:58   ` Maciej W. Rozycki
       [not found]     ` <xdt4l76ircncs6kh5ikhdsn5hsmh3wwceecl2pzg6zmqr7i2sm@slquforl5gfu>
       [not found]   ` <c5c35b74-bc56-e0f1-3608-05aac48f1be3@mirbsd.de>
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 38+ messages in thread
From: Maciej W. Rozycki @ 2025-06-20 22:58 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Andreas Schwab, Thorsten Glaser, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Martin Uecker, Christopher Bazley, eskil

Hi Alejandro,

> After the useful discussion with Eric and Paul, I've rewritten a draft
> of a proposal I had for realloc(3) for C2y.  Here it is (see below).

 I've been following all the previous discussion (despite not having been 
explicitly cc'd) and I'm yet going to read through and chew over your 
proposal, but not before next week as it's quite late into this one here 
already.  A thought has struck me however, at the high level.

 Given all the (understandable) fuss and the lack of symmetry (at least in 
some implementation variants) between `malloc(0)' and `realloc(p, 0)', and 
last but not least conflicting desires, both of which having their pros 
and cons, how about we actually fulfil the desires of both camps and come 
up with a set of entirely new APIs, say (1) `mallocn'/`reallocn' and (2) 
`mallocz'/`reallocz', that for zero-sized allocation requests consistently 
respectively:

(1) return NULL, in the case of `reallocn' having freed any previous 
    allocation,

(2) return a pointer to a valid allocation, forbidden to access and the 
    size of which might be zero, in the case of `reallocz' having freed or 
    possibly shrunk any previous allocation?

Implementations could then provide either semantics with their legacy 
`malloc'/`realloc' APIs, possibly following your proposal, mostly for 
software that does not ever care about zero-sized allocations, which I 
think is quite substantial a subset.

 It seems to me that the overhead for such separate APIs wouldn't be that 
high, and where suitable they could even be exported from system headers 
as macros or static always inline functions wrapping around the one core 
implementation of each, so as to let the compiler optimise away the 
uninterested case with many calls to these APIs where the compiler can 
statically prove size to be zero or nonzero.

 Thank you for your perseverance with this matter anyway, and have a good 
weekend!

  Maciej


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
  2025-06-20 22:31   ` [musl] " Christopher Bazley
@ 2025-06-21  1:59     ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-21  1:59 UTC (permalink / raw)
  To: Christopher Bazley
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker, eskil

[-- Attachment #1: Type: text/plain, Size: 13732 bytes --]

Hi Chris,

On Fri, Jun 20, 2025 at 11:31:45PM +0100, Christopher Bazley wrote:
> Hi Alex,
> 
> On Fri, Jun 20, 2025 at 10:26 PM Alejandro Colomar <alx@kernel.org> wrote:
> >         There are two kinds of code that call realloc(p,0).  One
> >         hard-codes the 0, and is used as a replacement of free(p).  This
> >         code ignores the return value, since it's unimportant.  This
> >         code currently produces a leak of 0 bytes plus associated
> 
> I have a feeling that I wrote something like this in one of my emails
> but I have since realised that the as-if rule allows "deallocates the
> old object pointed to by ptr and returns a pointer to a new object
> that has the size specified by size" to be a no-op: an implementation
> of realloc could return a pointer to the same heap block whenever the
> new requested size is less than or equal to the current size.
> Effectively the amount of memory leaked would then be bounded only by
> the maximum size of the allocation.

Yes, that could be a valid implementation.  Although the implementation
would be a bit stupid if it didn't allow that memory to be reclaimed by
another call to malloc(3).  Especially with a call with size 0, where
none of the old contents are alive anymore, and so any pointer would
work.

> >         metadata on platforms such as musl libc, where it returns a
> >         non-null pointer.  However, assuming that there are programs
> >         written with the knowledge that they won't ever be run on such
> >         platforms, we should take care of that, and make sure they don't
> >         leak.  A way of accomplishing this would be to recommend
> >         implementations to issue a diagnostic when realloc(3) is called
> >         with a hardcoded zero.  This is only an informal recommendation
> >         made by this proposal, as this is a matter of QoI, and the
> >         standard shouldn't say anything about it.  This would prevent
> >         this class of minor leaks.
> >
> >         Moreover, in glibc, realloc(p,0) may return non-null, in the
> >         case where p is NULL, so code must already take that into
> >         account, and thus code that simply takes realloc(p,0) as a
> >         synonym of free(p) is already leaky, as free(NULL) is a no-op,
> >         but realloc(NULL,0) allocates 0 bytes.
> 
> This behaviour does not sound good, but I think you are assuming
> something about the usage of realloc(p,0): might it be called if and
> only if p != NULL?

Yeah, one could call

	if (p != NULL)
		realloc(p, 0);

I somehow expect people to not be that insane.  :)

> 
> >         The other kind of code is in algorithms that realloc(3) an
> >         arbitrary size, which might eventually be zero.  This gets more
> >         complex.
> >
> >         Here's the code that should be written for AIX or glibc:
> >
> >                 errno = 0;
> >                 new = realloc(old, size);
> >                 if (new == NULL) {
> >                         if (errno == ENOMEM)
> >                                 free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         Failing to check for ENOMEM in these platforms before freeing
> >         the old pointer would result in a double-free.  If the program
> >         decides to continue using the old pointer instead of freeing it,
> >         it would result in a use-after-free.
> 
> The above code looks suspect to me anyway because it does 'goto fail'
> in a scenario where errno != ENOMEM, which presumably includes errno
> == 0, which should not be considered a failure.

Let's quote C17 (not C23 because it's UB):

<https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf#subsection.7.22.3>
C17::7.22.3p1:

	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.

It clearly says that it is considered an error.  It's a partial error,
because the object is successfully deallocated, but the new memory is
not allocated.

POSIX.1-2024 is slightly different: it says the function may consider it
an error, by reporting EINVAL.  However, the implementation is free to
not set errno at all.

In any case, as a programmer, I'd consider it an error.  I don't want to
treat a NULL pointer as a valid pointer, because something's going to
break further down when I pass this pointer around and compare it to
NULL.  So I better fail already soon.  It's about null pointer hygiene;
you know what I'm talking about.  ;)

> 
> Anyway, isn't there a simpler example that illustrates your point
> without relying on errno?
> 
> What about this:
> 
>                  new = realloc(old, size);
>                  if (new == NULL) {
>                          if (size != 0) {
>                                  free(old);
>                                  goto fail;
>                          }
>                  }
>                  ...
>                  free(new);

This is pedantically not valid.  An implementation might ENOMEM on
size==0 (let's say you're on an implementation that returns non-null,
and it wasn't able to find enough space for the metadata needed for the
allocation; in such a case, the old pointer must not be freed, as in any
other ENOMEM situations).  It would be weird, but not impossible.  In
such a case, your code would leak 'old'.

So, the only way to call realloc(p,s) portably today to POSIX systems is
by checking ENOMEM.

> If you are absolutely sure that ENOMEM is required for this case then
> the argument that such implementations are compliant with the ISO C
> standard is weaker than I initially realised.

I think you need it.

> 
> >         In the platforms where realloc(p,0) returns non-null, such as
> >         the BSDs or musl libc, it is simpler to handle it:
> >
> >                 new = realloc(old, size);
> >                 if (new == NULL) {  // errno is ENOMEM
> >                         free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         Whenever the result is a null pointer, these platforms are
> >         reporting an ENOMEM error, and thus it is superfluous to check
> >         errno there.
> >
> >         Most code is written in this way, even if run on platforms
> >         returning a null pointer.  This is because most programmers are
> >         just unaware of this problem.
> 
> Also perhaps because ENOMEM isn't part of ISO standard C therefore it
> is not necessarily defined. (e.g., it is not defined in the headers
> for the Norcroft C compiler for RISC OS.)

They should define it now.  As for old code, if they didn't have ENOMEM
available, they didn't have a portable way to call realloc(3).  They
could use your version, but it could leak on platforms that don't return
NULL.  Or they could just use the realloc(p,n?n:1) trick, which is
simpler, and works like a charm.

> It's interesting to think about why ENOMEM might not be part of the
> ISO standard. I suspect the reason is that it was not believed to be
> necessary for completeness of any of the standard library interfaces.
> Your email suggests otherwise.

Indeed.  Actually, it wouldn't be necessariy if standards and
implementations hadn't broken realloc(3) so much.  In an ideal world,
NULL would be enough to know that realloc(3) failed.  But we're not in
that world.  Current code needs to check ENOMEM.  And thus, the new
specification should use ENOMEM, to support that code.  We need an
implementation that is fully backwards-compatible.  Otherwise, I'm
worried that we won't convince the implementations to risk introducing
silent bugs in code that works today.

> >         If the realloc(3) specification was changed to require that
> 
> "Were", not "was". Sorry for being pedantic.

Thanks!  I'm not a native English speaker; these corrections help.  :)

> >         realloc(p,0) returns non-null on success, and that realloc(p,0)
> >         only fails when out-of-memory, and to require that it sets
> >         errno to ENOMEM, then code written for AIX or glibc would
> 
> You can't require that errno be set to a value that does not exist in
> the standard. I see you are planning to add it, but I'm not yet
> convinced that is necessary.

See above.  I had previously thought that it wasn't necessary, but after
spending some time thinking about it today, I'm pretty sure we need it.

> >         continue working just fine, since the errno check would be
> >         redundant with the null check.  Simply, the conditional
> >         (errno == ENOMEM) would always be true when (new == NULL).
> >
> >         This makes handling of realloc(3) as straightforward as one
> >         would expect, with only two states: success or error.
> >
> >         The resulting wording in the standard is also much simpler, as
> >         it doesn't need to define so many special cases.
> >
> >         For consistency, all the other allocation functions are updated
> >         to both return an .
> 
> Missing text?

Yep.  I have it fixed for the next revision:

	diff --git i/alx-0029.txt w/alx-0029.txt
	index a1a96c4..f8835cf 100644
	--- i/alx-0029.txt
	+++ w/alx-0029.txt
	@@ -31,7 +31,6 @@ Author
		Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
		Cc: Joseph Myers <josmyers@redhat.com>
		Cc: Florian Weimer <fweimer@redhat.com>
	-       Cc: Laurent Bercot <ska-dietlibc@skarnet.org>
		Cc: Andreas Schwab <schwab@suse.de>
		Cc: Thorsten Glaser <tg@mirbsd.de>
		Cc: Eric Blake <eblake@redhat.com>
	@@ -58,6 +57,10 @@ History
		r1 (2025-06-20):
		-  Full rewrite after the recent glibc discussion.
	 
	+       r2 ():
	+       -  Remove CC.
	+       -  wfix.
	+
	 See also
		<https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
		<https://sourceware.org/pipermail/libc-alpha/1999-April/000956.html>
	@@ -192,7 +195,7 @@ Description
		it doesn't need to define so many special cases.
	 
		For consistency, all the other allocation functions are updated
	-       to both return an .
	+       to both return a null pointer and set errno to ENOMEM.
	 
	 Prior art
	     gnulib

> 
> > Prior art
> >     gnulib
> >         gnulib provides the realloc-posix module, which aims to wrap the
> >         system realloc(3) and reallocarray(3) functions so that they
> >         behave in a POSIX-complying manner.
> >
> >         It previously behaved like glibc.  After I reported that it was
> >         non-conforming to POSIX, we discussed the best way forward,
> >         which we agreed was the same direction that this paper is
> >         proposing now for C2y.  The implementation was changed in
> >
> >                 gnulib.git d884e6fc4a60 (2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
> >
> >         There have been no regression reports since then, as we
> >         expected.
> >
> >     Unix V7
> >         The proposed behavior is the one endorsed by Doug McIlroy, the
> >         author of the original implementation of realloc(3) in Unix V7,
> >         and also present in the BSDs.
> >
> > Design decisions
> >         This change needs three changes, which can be applied both at
> >         once, or in two separate steps.
> >
> >         The first step would make realloc(p,s) be consistent with
> >         free(p) and malloc(s), including when p is a null pointer, when
> >         s is zero, and also when both corner cases happen at the same
> >         time.  This change would already turn the implementations where
> >         malloc(0) returns non-null into the end goal we have.
> >
> >         The first step would require changes to (at least) the following
> >         implementations: glibc, Bionic, Windows.
> >
> >         The second step would be to require that malloc(0) returns a
> >         non-null pointer.
> >
> >         The second step would require changes to (at least) the
> >         following implementations: AIX.
> >
> >         The third step would be to require that on error, errno is set
> >         to ENOMEM.
> >
> >         This proposal has merged all steps into a single proposal.
> >
> >         This proposal also needs to add ENOMEM to the standard, since it
> >         hasn't been standardized yet.
> 
> I think this change would be better served by a separate proposal
> unless you believe both:
> - that ENOMEM serves a special purpose for realloc, and
> - that WG14 can only be persuaded to accept ENOMEM on account of that
> special purpose.

For backwards compatiblity, I think we need to add ENOMEM.  Otherwise,
code that is perfect today might have small issues with the new
specification.

And of course, if we have issues with the new specification, it won't
even be accepted or implemented.

> I have doubts about both points.
> 
> > Future directions
> >         This proposal, by specifying realloc(3) as-if by calling
> >         free(3) and malloc(3), makes it redundant several mentions of
> 
> Extra 'it'.

Thanks!

> 
> Overall, I wholeheartedly support your direction.

Thanks!  :-)


Have a lovely day!
Alex

> 
> Chris

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
       [not found]         ` <euw6h6yxp6mghwcajrfvp7fzvafazyafl4jtbjf334kg6kfkfu@x5tkgo6kfomt>
@ 2025-06-21  3:50           ` Paul Eggert
  0 siblings, 0 replies; 38+ messages in thread
From: Paul Eggert @ 2025-06-21  3:50 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Thorsten Glaser, libc-alpha, bug-gnulib, musl,
	наб,
	Douglas McIlroy, Robert Seacord, Elliott Hughes, Bruno Haible,
	JeanHeyd Meneide, Rich Felker, Adhemerval Zanella Netto,
	Joseph Myers, Florian Weimer, Laurent Bercot, Andreas Schwab,
	Eric Blake, Vincent Lefevre, Mark Harris, Collin Funk,
	Wilco Dijkstra, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil

On 2025-06-20 19:42, Alejandro Colomar wrote:

>> If ENOMEM is really needed, its presence should be justified in the
>> proposal.
> 
> I wrote it, although maybe it would need to be clearer?

It would need reworking as it didn't feel like a justification to me.


> Here's the part that justifies it:
> 
> 	Here's the code that should be written for AIX or glibc:
> 
> 		errno = 0;
> 		new = realloc(old, size);
> 		if (new == NULL) {
> 			if (errno == ENOMEM)
> 				free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	[...]
> 
> 	If the realloc(3) specification was changed to require that
> 	realloc(p,0) returns non-null on success, and that realloc(p,0)
> 	only fails when out-of-memory, and to require that it sets
> 	errno to ENOMEM, then code written for AIX or glibc would
> 	continue working just fine, since the errno check would be
> 	redundant with the null check.  Simply, the conditional
> 	(errno == ENOMEM) would always be true when (new == NULL).
> 
> If that old code runs on a new system that doesn't set ENOMEM, it will
> leak 'old'.  Admittedly, that code is currently only portable to POSIX
> systems, which already require ENOMEM, and I don't expect POSIX would
> lift that requirement (and would recommend not lifting it), so I expect
> people won't run that code in arbitrary C2y platforms.

But this is exactly why the main proposal (i.e., null if-and-only-if 
failure) shouldn't require ENOMEM. The C standardizers have already 
thought through the ENOMEM issue and decided not to require ENOMEM. 
Whatever reasons they have, won't change because of the main proposal.

ENOMEM belongs to POSIX, and POSIX will retain ENOMEM regardless of 
whether C2y accepts the main proposal. We shouldn't try to link the two 
proposals together in the C standardization process, as that's more 
likely to gum up the works entirely.


> I added the ENOMEM part because of the above, to make sure that the new
> realloc(3) specification is fully backwards compatible to every existing
> implementation, so that you can take your AIX or glibc or musl or
> whatever code, and say "hey, I'll run this code on any C2y-conforming
> platform; it should Just Work".

Those platforms are all POSIXish, and you'll be able to say "hey I'll 
run this code on any POSIX-202y system (which extends C2y) and it should 
Just Work". That's all anyone can reasonably expect. One can't 
reasonably expect to run a POSIXish program on any C2y system and let's 
not try to make that a goal.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                       ` <2sqn2ggwgtgjhrd7p57ipbxqe7ncpk3c5rmyvvqlumvyecsk5q@ufffzvlrnvpk>
  2025-06-20  2:11                         ` Vincent Lefevre
  2025-06-20 13:42                         ` Mark Harris
@ 2025-06-21  3:57                         ` Sam James
       [not found]                         ` <ymigejkdbyrxohd5chrigpfvztnia2nw4u3jmdiw6vke2xs3me@xb5t6hevzuba>
  3 siblings, 0 replies; 38+ messages in thread
From: Sam James @ 2025-06-21  3:57 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

Alejandro Colomar <alx@kernel.org> writes:

> [...]
>
> But the glibc maintainers mentioned that they're investigating about it
> in distros, so I guess we'll eventually have the results of their
> investigation.
>

To manage expectations: I haven't seen anyone say they're going to work
on this. I recall Sid mentioning it *could* be done (not offering to do
it) and Adhemerval made a similar remark, but I don't think anyone has
said they're undertaking this work.

If I've missed some other remark (very possible with the length of the
thread!), let me know of course.

sam

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
       [not found]     ` <xdt4l76ircncs6kh5ikhdsn5hsmh3wwceecl2pzg6zmqr7i2sm@slquforl5gfu>
@ 2025-06-21 14:49       ` Markus Wichmann
  2025-06-21 16:27         ` Rich Felker
  0 siblings, 1 reply; 38+ messages in thread
From: Markus Wichmann @ 2025-06-21 14:49 UTC (permalink / raw)
  To: musl
  Cc: Maciej W. Rozycki, libc-alpha, bug-gnulib, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Andreas Schwab, Thorsten Glaser, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Martin Uecker, Christopher Bazley, eskil

Am Sat, Jun 21, 2025 at 04:07:54AM +0200 schrieb Alejandro Colomar:
> I honestly still don't see the point in the camp returning NULL.  The
> only reason it hasn't died, I think, is because of fear of breaking
> existing code, but I don't see anyone asking for that behavior.
> 

I invert the question: What is the point of requesting zero bytes? If
you just want a pointer you cannot deref, but can validly plug into both
realloc() and free(), I have this perfectly good null pointer right
here. You can even statically initialize your variables with it. And you
can easily tell it apart from pointers you can dereference.

I see malloc(0) as an error. According to all standards I could get my
hands on, the argument to malloc is supposed to be the size of an
object, and in C, there are no objects without type, and no zero-sized
types. Maybe that's different in C++, I don't know. I have read a bit of
C code in my life, and have written some as well, and debugged even more
of it. I cannot recall an instance of anyone ever requesting to allocate
zero bytes except in error (e.g. uncaught overflow).

Indeed, a strict reading of the spec would be that the argument must be
the result of a sizeof expression, and the common idiom

A *a = malloc(sizeof (A) + sizeof (B));
B *b = (B *)(a + 1);

is undefined. And indeed, it potentially crashes on strict-alignment
architectures if alignof(B) > alignof(A).

Back to zero-sized allocations: The fact that they were traditionally
supported on UNIX means nothing if they were always undefined. At that
point it just becomes a quirk of the implementation, but nothing an
application should depend on.

The C89 mandate to free the pointer in case of zero-sized realloc (which
I read as a command to *only* free the pointer and not do anything else)
seems actively harmful: If an application can be tricked into doing
that, and an implementation chooses to return the now freed pointer
(since realloc must return /something/), then the application now holds
a pointer it thinks is still valid, but is actually dangling.

The way C89 (or rather FIPS160, which is the version I've read) has
added the realloc-0-frees mandate, it looks like a badly thought through
afterthought. But then, C89 also contains sprintf() and gets(), so badly
thought through afterthoughts are certainly not a novelty to that
particular writ.

All standards after it have tinkered with the semantics of zero-sized
allocation, to the point that C23 just made it explicitly undefined. As
application developer, what inference do I draw from this, except to
avoid zero-sized allocation like the plague? If anyone actually writes
"realloc(p, 0)" intending it to be the same as "free(p)", I would tell
them to then write what they mean and stop being so clever.

As implementation developer, I would therefore treat these requests as
errors, and do the appropriate thing: Return the error value and set
errno to EINVAL (and have no further side effects). And such an
implementation conforms to everything from C99 onwards.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: alx-0029r1 - Restore the traditional realloc(3) specification
  2025-06-21 14:49       ` Markus Wichmann
@ 2025-06-21 16:27         ` Rich Felker
  0 siblings, 0 replies; 38+ messages in thread
From: Rich Felker @ 2025-06-21 16:27 UTC (permalink / raw)
  To: Markus Wichmann
  Cc: musl, Maciej W. Rozycki, libc-alpha, bug-gnulib,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Adhemerval Zanella Netto,
	Joseph Myers, Florian Weimer, Andreas Schwab, Thorsten Glaser,
	Eric Blake, Vincent Lefevre, Mark Harris, Collin Funk,
	Wilco Dijkstra, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Martin Uecker,
	Christopher Bazley, eskil

On Sat, Jun 21, 2025 at 04:49:17PM +0200, Markus Wichmann wrote:
> Am Sat, Jun 21, 2025 at 04:07:54AM +0200 schrieb Alejandro Colomar:
> > I honestly still don't see the point in the camp returning NULL.  The
> > only reason it hasn't died, I think, is because of fear of breaking
> > existing code, but I don't see anyone asking for that behavior.
> > 
> 
> I invert the question: What is the point of requesting zero bytes? If
> you just want a pointer you cannot deref, but can validly plug into both
> realloc() and free(), I have this perfectly good null pointer right
> here. You can even statically initialize your variables with it. And you
> can easily tell it apart from pointers you can dereference.
> 
> I see malloc(0) as an error. According to all standards I could get my
> hands on, the argument to malloc is supposed to be the size of an
> object, and in C, there are no objects without type, and no zero-sized
> types. Maybe that's different in C++, I don't know. I have read a bit of
> C code in my life, and have written some as well, and debugged even more
> of it. I cannot recall an instance of anyone ever requesting to allocate
> zero bytes except in error (e.g. uncaught overflow).

Can we please not relitigate why people want this to work right? It's
actually not about any need for zero-sized allocations, but rather a
need for contractual consistency and avoiding violations of
least-surprise principle.

If malloc(0) or realloc(p,0) can return a null pointer for a condition
that's not a "failure", this means you eiter need error-path logic to
distinguish the "failure" from the "non-failure", or you need
entry-path logic to make sure 0 is never passed to malloc or realloc
as the result of any size computation.

We all know it's hard enough to get programmers to write even simple
error-path logic right with respect to malloc. So much code doesn't
even check the return value at all, or just aborts on a null return.

Likewise, it's hard enough to get programmers to write even simple
entry-path logic for allocation, avoiding integer overflows in the
computation of the size needed. Having to go to extra effort to also
avoid passing zero just makes a new non-forced footgun on top of the
other footguns that are more "essential".

Nobody wants the "make it worse" change you're asking for. So please
don't derail the work of people actually trying to make it better. At
least "we don't want to impose compatibility burdens on implementors
by forcing them to change something" is a reasonable argument some
folks might have against doing something here. "Let's make it worse
for nothing but ideological reasons" is not.

Rich

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r3 - Restore the traditional realloc(3) specification
       [not found]     ` <p55v5kpblnzvg4eatx2hmlrsbjkybtd4syy7zbjiza6wv4xv2u@o25g6qru3ppx>
@ 2025-06-24  9:07       ` Florian Weimer
  2025-06-24  9:54         ` Bruno Haible
  2025-06-24 14:18         ` Alejandro Colomar
       [not found]       ` <lqwifu3d5rcevgbzskyxgqlxceznlougry6tbtote5xbt37u7s@kynjo4ncdocj>
  1 sibling, 2 replies; 38+ messages in thread
From: Florian Weimer @ 2025-06-24  9:07 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Eric Blake, Vincent Lefevre, Mark Harris,
	Collin Funk, Wilco Dijkstra, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil, Daniel Krügler,
	Kees Cook, Valdis Klētnieks

* Alejandro Colomar:

> Here's a new revision of the proposal.  I've removed ENOMEM, since it's
> not strictly necessary; it's only necessary that those systems that
> already set it continue setting it (and my proposal for POSIX will
> certainly include ENOMEM).

As far as I can see, this changes specification across all allocation
functions and requires them to be able to produce zero-sized objects.
Previously, the discussion was about changing realloc only.

Is this really the right direction, given that

  int a[n];

is still undefined, and that C does not support zero-sized objects in
general?

Wouldn't it be more consistent to move in the other direction, and
require that allocations of zero size fail because C does not support
zero-sized objects?

(This is why I don't want to make any changes today—we just don't know
what the tightened specification will look like in the published
standard.  There are just too many totally reasonable variations.)

Thanks,
Florian


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r3 - Restore the traditional realloc(3) specification
  2025-06-24  9:07       ` [musl] Re: alx-0029r3 " Florian Weimer
@ 2025-06-24  9:54         ` Bruno Haible
  2025-06-24 14:18         ` Alejandro Colomar
  1 sibling, 0 replies; 38+ messages in thread
From: Bruno Haible @ 2025-06-24  9:54 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Alejandro Colomar, libc-alpha, bug-gnulib, musl,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	JeanHeyd Meneide, Rich Felker, Adhemerval Zanella Netto,
	Joseph Myers, Laurent Bercot, Andreas Schwab, Eric Blake,
	Vincent Lefevre, Mark Harris, Collin Funk, Wilco Dijkstra,
	DJ Delorie, Cristian Rodríguez, Siddhesh Poyarekar,
	Sam James, Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

Florian Weimer wrote:
> Wouldn't it be more consistent to move in the other direction, and
> require that allocations of zero size fail because C does not support
> zero-sized objects?

This would be a terrible idea. In all programming domains, the special
case of 0 needs to be specified in a way that most naturally extends
the sequence of cases 1, 2, 3, ... If this is not done, application
code must constantly have special code for 0, and since programmers
are not good at doing this consistently, this would produce a large
number of bugs.

So, it is the task of the ISO C committee to *simplify* application
programming by *integrating* the case of 0 smoothly with the cases
1, 2, 3, ...

They are not entirely there yet, but the direction (e.g. of N3322)
is the correct one.

>   int a[n];
> 
> is still undefined, and that C does not support zero-sized objects in
> general?

They are working on it; they are just not there yet.

Bruno




^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r3 - Restore the traditional realloc(3) specification
  2025-06-24  9:07       ` [musl] Re: alx-0029r3 " Florian Weimer
  2025-06-24  9:54         ` Bruno Haible
@ 2025-06-24 14:18         ` Alejandro Colomar
       [not found]           ` <CAH8yC8n4Xf1uvcNCvycvrn4SvjWN2ttXFW6-75tyEbtUO916MQ@mail.gmail.com>
  1 sibling, 1 reply; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-24 14:18 UTC (permalink / raw)
  To: Florian Weimer
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Eric Blake, Vincent Lefevre, Mark Harris,
	Collin Funk, Wilco Dijkstra, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil, Daniel Krügler,
	Kees Cook, Valdis Klētnieks

[-- Attachment #1: Type: text/plain, Size: 4273 bytes --]

Hi Florian,

On Tue, Jun 24, 2025 at 11:07:53AM +0200, Florian Weimer wrote:
> * Alejandro Colomar:
> 
> > Here's a new revision of the proposal.  I've removed ENOMEM, since it's
> > not strictly necessary; it's only necessary that those systems that
> > already set it continue setting it (and my proposal for POSIX will
> > certainly include ENOMEM).
> 
> As far as I can see, this changes specification across all allocation
> functions and requires them to be able to produce zero-sized objects.
> Previously, the discussion was about changing realloc only.

Yes, but the changes in malloc(0) are a no-op for most implementations,
including glibc.

AIX is the only one we know that would need to be updated.  Plus maybe
some small embedded imoplementations.

The previous discussion was about realloc(p,0) because that's the main
issue, which results in vulnerabilities, but committee members asked me
to merge both proposals at once --I had a _separate_ proposal for
malloc(0), which of course I didn't mention to glibc, as it's not a
problem here--, so that people would see the entire goal at once, so as
to avoid confusion.

But continue reading.

> Is this really the right direction, given that
> 
>   int a[n];
> 
> is still undefined, and that C does not support zero-sized objects in
> general?

My plan is to address that after realloc(p,0).

In fact, Doug McIlroy suggested me in private to try to propose
standardizing

	int a[0];

first, and then use it to convince that malloc(0) and realloc(p,0) should
follow.

However, I see more opposition for that than for malloc(0) and
realloc(0).  One of the reasons is there are some platforms that
support malloc(0) and realloc(p,0), but none that support a[0].

> 
> Wouldn't it be more consistent to move in the other direction, and
> require that allocations of zero size fail because C does not support
> zero-sized objects?

That's what some people have attempted since the times of SysV and C89.
Three decades after, people haven't achieved that, and we see the
fallout.

Plus, the only direction in which moving is relatively safe is from
returning-NULL behavior to returning-non-null behavior.  Consider this
code written for a realloc(p,0) that returns NULL:

	errno = 0;
	new = realloc(old, n);
	if (new == NULL) {
		if (errno == ENOMEM)
			free(old);
		goto fail;
	}
	...
	free(new);

If you suddenly return non-null from realloc(p,0), that code will
continue behaving well.  In some other cases, as you can see in my
proposal, a memory leak would be introduced, which is a very mild
problem.

Now see some code written for platforms like musl or the BSDs:

	new = realloc(old, n);
	if (new == NULL)
		free(old);
		goto fail;
	}
	...
	free(new);

Now, if realloc(p,0) starts returning NULL and freeing the object, like
in glibc, line 3 will result in a double-free.  This is a serious bug,
which can result in RCE vulnerabilities.

See the Whatsapp RCE mentioned in the proposal.  Here's another link
that talks about it which Bruno found, which mentions reallocarray():
<https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>

So, we can't move in the direction of glibc or AIX, as it would break
the world.

> (This is why I don't want to make any changes today—we just don't know
> what the tightened specification will look like in the published
> standard.  There are just too many totally reasonable variations.)

The thing is, someone in the C Committee asked me yesterday if glibc is
really into this if the committee agrees to move to the BSD behavior.

If you --glibc maintainers-- publicly agree to do this change with the
condition that the C Committee standardizes exactly this first, I'm
pretty sure I can convince the committee to standardize it.  The
committee is worried that if it standardizes that, then glibc might
still ignore it.

So, both parties are worried that the other might not agree.  The
solution I see is that you agree to the change conditional to having the
change in the standard first, and then the committee can change the
standard.

Would you agree to that?


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r3 - Restore the traditional realloc(3) specification
       [not found]       ` <lqwifu3d5rcevgbzskyxgqlxceznlougry6tbtote5xbt37u7s@kynjo4ncdocj>
@ 2025-06-24 23:01         ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-24 23:01 UTC (permalink / raw)
  To: Eric Blake
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Vincent Lefevre, Mark Harris,
	Collin Funk, Wilco Dijkstra, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil, Daniel Krügler,
	Kees Cook, Valdis Klētnieks

[-- Attachment #1: Type: text/plain, Size: 9748 bytes --]

Hi Eric,

On Tue, Jun 24, 2025 at 04:18:40PM -0500, Eric Blake wrote:
> On Tue, Jun 24, 2025 at 07:01:50AM +0200, Alejandro Colomar wrote:

[...]

> Some feedback to consider:
> ...
> 
> > Description

[...]

> > 	[3] <https://gbhackers.com/whatsapp-double-free-vulnerability/>
> > 
> > 	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.
> 
> It may be worth specifically mentioning that glibc 2.1 and earlier
> also had that behavior, even though it was an independent
> implementation not derived from Unix V7; and that the _only_ reason
> glibc 2.2 and later changed in 2000 to just freeing p instead of
> returning a result like malloc(0) was because someone argued that the
> C89 wording required that change, despite the new wording in C99 in
> discussion under the time that was trying to remove the warts in the
> C89 definition.

Certainly; I'll add that.

[...]

> > 	Most code is written in this way, even if run on platforms
> > 	returning a null pointer.  This is because most programmers are
> > 	just unaware of this problem.
> 
> It may also be worth pointing out that any time code behaves one way
> for 3, 2, 1, and then suddenly changes behavior at 0, it is much
> harder to code the use of that interface correctly; when compared to
> an interface where each successive call is merely one byte less in
> effect than the previous-larger call.

Yup.

[...]

> > Prior art

[...]

> >     Unix V7
> > 	The proposed behavior is the one endorsed by Doug McIlroy, the
> > 	author of the original implementation of realloc(3) in Unix V7,
> > 	and also present in the BSDs.
> 
> Would calling out glibc 2.1 as prior art help?

Yup.

> > Design decisions
> > 	This change needs three changes, which can be applied all at
> > 	once, or in separate steps.
> 
> You document "three" here...

Yeah, I forgot to s/three/two/ when I removed the requirement to set
ENOMEM.

[...]

> ...and no mention of the third step.  You'll want to clean that up.

Yup.

[...]

> > Caveats
> >     n?n:1
> > 	Code written today should be careful, in case it can run on
> > 	older systems that are not fixed to comply with this stricter
> > 	specification.  Thus, code written today should call realloc(3)
> > 	similar to this:
> > 
> > 		realloc(p, n?n:1);
> > 
> > 	When all existing implementations are fixed to comply with this
> > 	stricter specification, that workaround can be removed.
> > 
> >     ENOMEM
> > 	Existing implementations that set errno to ENOMEM must continue
> > 	doing so when the input pointer is not freed.  If they didn't,
> > 	code that is currently portable to all POSIX systems
> > 
> > 		errno = 0;
> > 		new = realloc(old, size);
> > 		if (new == NULL) {
> > 			if (errno == ENOMEM)
> > 				free(old);
> > 			goto fail;
> > 		}
> > 		...
> > 		free(new);
> > 
> > 	would leak on error.
> 
> Would it also be worth mentioning (either here or as a footnote to be
> added in the standard) that while atypical, realloc() is allowed to
> fail with ENOMEM even when the new size is smaller than the previous
> size of the pointer?  This might be seen as a non-intuitive result,
> but as Rich Felker pointed out, there ARE implementations of malloc()
> that use alignment properties on the returned pointer itself as part
> of the information encoding how much memory the region points to (such
> as whether the allocation comes from mmap or the heap, for example),
> and the standard should not be precluding these types of
> implementations.  With such a mention in place, it may also be worth
> mentioning that when new==NULL, it is not necessary to call free(old)
> immediately, if the programmer would rather ignore the fact that the
> system cannot move the allocation to a more efficient location and
> that the tail of the old pointer is now wasted space.

Yeah, that would make sense in a footnote.

[...]

> > 	@@ Returns, p3
> > 	 The <b>calloc</b> function returns
> > 	-either
> > 	 a pointer to the allocated space
> > 	+on success.
> > 	-or a null pointer
> > 	-if
> > 	+If
> > 	 the space cannot be allocated
> > 	 or if the product <tt>nmemb * size</tt>
> > 	-would wraparound <b>size_t</b>.
> > 	+would wraparound <b>size_t</b>,
> > 	+a null pointer is returned.
> 
> Not part of this paper, but would it make sense for implementations
> that return different errno for the two different classes of failures
> here?  ENOMEM when the pointer can't be allocated, and EINVAL (or
> maybe ERANGE or EOVERFLOW) when nmemb*size overflows?

If designing realloc(3) from scratch, it could make sense.  But for
backwards compatibility, we should use ENOMEM for all errors that keep
the old pointer alive.

That's because reallocarray(3) uses ENOMEM for the overflow case too,
and so, if some code depends on that, we could keep it working.  I
expect the consequence wouldn't be terrible if we change that --I expect
at most a leak--, but I'm not sure; we'd have to be careful.

For example, this code would be a portable way to call reallocarray(3)
in POSIX:

	errno = 0;
	new = reallocarray(old, n, size);
	if (new == NULL) {
		if (errno == ENOMEM)
			free(old);
		goto fail;
	}
	...
	free(new);

Using EOVERFLOW for n*size overflow would result in a leak of 'old' when
the size overflows.

We could decide that we can live with that leak, in return for a better
future where programs can differentiate between "OOM will trigger soon"
and "I just asked for an insane amount of memory".

Luckily, ISO C doesn't know about ENOMEM, so we have some time to talk
about it after fixing realloc(3) in ISO C.

> If C2y standardizes reallocarray(), then this becomes important.
> Without sane errno values, it is impossible to tell whether
> reallocarray() failed due to the inability to allocate the new
> pointer, or whether it failed because the parameters overflowed and no
> reallocation could be attempted.  In fact, glibc documents that
> attempting to malloc(PTRDIFF_MAX+1 bytes is treated as a failure, even
> if that value is positive and less than the total amount of memory
> available in the system, because objects cannot be so large as to
> cause problems when computing pointer differences.  But as long as the
> interface is documented as leaving the old pointer unchanged on ANY
> failures (whether allocation or overflow), then the semantics are
> still easy to work with even when not having errno to rely on.

Yeah, I think we have time to discuss this, as NULL will mean error, and
thus 'old' be unchanged.  That is, if and only if realloc(3) returns
NULL, the original pointer should remain unchanged, per my proposal.

> >     7.25.4.7  The malloc function
> > 	@@ Returns, p3
> > 	 The <b>malloc</b> function returns
> > 	-either
> > 	-a null pointer
> > 	-or
> > 	-a pointer to the allocated space.
> > 	+a pointer to the allocated space
> > 	+on success.
> > 	+If
> > 	+the space cannot be allocated,
> > 	+a null pointer is returned.
> > 
> >     7.25.4.8  The realloc function
> > 	@@ Description, p2
> > 	 The <b>realloc</b> function
> > 	 deallocates the old object pointed to by <tt>ptr</tt>
> > 	+as if by a call to <b>free</b>,
> > 	 and returns a pointer to a new object
> > 	-that has the size specified by <tt>size</tt>.
> > 	+that has the size specified by <tt>size</tt>
> > 	+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.
> > 
> > 	@@ 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.
> > 
> > 	@@ Returns, p4
> > 	 The <b>realloc</b> function returns
> > 	 a pointer to the new object
> > 	 (which can have the same value
> > 	-as a pointer to the old object),
> > 	+as a pointer to the old object)
> > 	+on success.
> > 	-or
> > 	+If
> > 	+space cannot be allocated,
> > 	 a null pointer
> > 	-if the new object has not been allocated.
> > 	+is returned.
> 
> I'm liking the direction this proposal is headed in.  If it is down to
> a question of whether glibc or the C standard will blink first, I'm
> hoping that we can get some agreement from both sides, rather than
> being stuck in a stalemate with each arguing that the other is the
> reason to not fix things.

Thanks a lot!  I feel like we're closer to reach that.



Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] alx-0029r4 - Restore the traditional realloc(3) specification
  2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
                     ` (3 preceding siblings ...)
       [not found]   ` <limjtao3jpge6hrrjliko4w6p5t7cfpbc3m3etodqgsxayi3hw@gv4eml5icqb5>
@ 2025-06-25  1:58   ` Alejandro Colomar
       [not found]     ` <u4vvv6oflabxrzaxqt5axeuiit4zpyyidmzn7zxz2sswjcuaqs@5xiezwem7mds>
       [not found]   ` <ttmksxnr4ojqqkereep5j5vkakz5wg5e24mjvbllj6u5ibvn5k@e7jslgr5dt2b>
       [not found]   ` <vl4fdi3ohhclxsgjhzz27owlxl7dh3gnjslykaiphwta6f66cc@alqxmrejng53>
  6 siblings, 1 reply; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-25  1:58 UTC (permalink / raw)
  To: libc-alpha, Eric Blake, Florian Weimer
  Cc: bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Thorsten Glaser, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil

[-- Attachment #1: Type: text/plain, Size: 18583 bytes --]

Hi!

Here's a revision addressing a few things:

-  Eric's comments for adding stuff to the rationale and prior art.
-  Added a better link for the Whatsapp RCE, which specifically mentions
   reallocarray(3).
-  Add a footnote mentioning that realloc(3) is allowed to fail while
   shrinking.

Eric, I could write something similar for POSIX.  Do you prefer to do it
in parallel, or maybe after this is discussed in the C Committee meeting
in Brno (2025-08)?


Have a lovely day!
Alex

---
Name
	alx-0029r4 - Restore the traditional realloc(3) specification

Principles
	-  Uphold the character of the language
	-  Keep the language small and simple
	-  Facilitate portability
	-  Avoid ambiguities
	-  Pay attention to performance
	-  Codify existing practice to address evident deficiencies.
	-  Do not prefer any implementation over others
	-  Ease migration to newer language editions
	-  Avoid quiet changes
	-  Enable secure programming

Category
	Remove UB.

Author
	Alejandro Colomar <alx@kernel.org>

	Cc: <bug-gnulib@gnu.org>
	Cc: <musl@lists.openwall.com>
	Cc: <libc-alpha@sourceware.org>
	Cc: наб <nabijaczleweli@nabijaczleweli.xyz>
	Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
	Cc: Paul Eggert <eggert@cs.ucla.edu>
	Cc: Robert Seacord <rcseacord@gmail.com>
	Cc: Elliott Hughes <enh@google.com>
	Cc: Bruno Haible <bruno@clisp.org>
	Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
	Cc: Rich Felker <dalias@libc.org>
	Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
	Cc: Joseph Myers <josmyers@redhat.com>
	Cc: Florian Weimer <fweimer@redhat.com>
	Cc: Andreas Schwab <schwab@suse.de>
	Cc: Thorsten Glaser <tg@mirbsd.de>
	Cc: Eric Blake <eblake@redhat.com>
	Cc: Vincent Lefevre <vincent@vinc17.net>
	Cc: Mark Harris <mark.hsj@gmail.com>
	Cc: Collin Funk <collin.funk1@gmail.com>
	Cc: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
	Cc: DJ Delorie <dj@redhat.com>
	Cc: Cristian Rodríguez <cristian@rodriguez.im>
	Cc: Siddhesh Poyarekar <siddhesh@gotplt.org>
	Cc: Sam James <sam@gentoo.org>
	Cc: Mark Wielaard <mark@klomp.org>
	Cc: "Maciej W. Rozycki" <macro@redhat.com>
	Cc: Martin Uecker <ma.uecker@gmail.com>
	Cc: Christopher Bazley <chris.bazley.wg14@gmail.com>
	Cc: <eskil@obsession.se>
	Cc: Daniel Krügler <daniel.kruegler@googlemail.com>
	Cc: Kees Cook <keescook@chromium.org>
	Cc: Valdis Klētnieks <valdis.kletnieks@vt.edu>

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

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

	r1 (2025-06-20):
	-  Full rewrite after the recent glibc discussion.

	r2 (2025-06-21):
	-  Remove CC.  Add CC.
	-  wfix.
	-  Drop quote.
	-  Add a few more principles
	-  Clarify why ENOMEM is used in this proposal, and make it
	   optional.
	-  Mention exceptional leak in code checking (size != 0).
	-  Clarify that part of the description of realloc can be
	   editorially removed after this change.

	r3 (2025-06-23):
	-  Fix diff missing line.
	-  Remove ENOMEM from the proposal.
	-  Clarify that ENOMEM should be retained by platforms already
	   using it.
	-  Add mention that LLVM's address sanitizer will catch the leak
	   mentioned in r2.
	-  Add links to real bugs (including an RCE bug).

	r4 (2025-06-24):
	-  Use a better link for the Whatsapp RCE.
	-  s/Description/Rationale/
	-  wfix
	-  Mention that glibc <2.2 had the BSD behavior.
	-  Add footnote that realloc(3) may fail while shrinking.

See also
	<https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
	<https://sourceware.org/pipermail/libc-alpha/1999-April/000956.html>
	<https://inbox.sourceware.org/libc-alpha/20241019014002.3684656-1-siddhesh@sourceware.org/T/#u>
	<https://inbox.sourceware.org/libc-alpha/qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv/T/#u>
	<https://github.com/bminor/glibc/commit/7c2b945e1fd64e0a5a4dbd6ae6592a7314dcd4b5>
	<https://github.com/llvm/llvm-project/issues/113065>
	<https://www.austingroupbugs.net/view.php?id=400>
	<https://www.austingroupbugs.net/view.php?id=526>
	<https://www.austingroupbugs.net/view.php?id=688>
	<https://sourceware.org/bugzilla/show_bug.cgi?id=12547>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n868.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2438.htm>
	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf>
	<https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/realloc.html>
	<https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/functions/realloc.html>
	<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120744>
	<https://lore.kernel.org/lkml/20220213182443.4037039-1-keescook@chromium.org/>
	<https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>
	<https://gbhackers.com/whatsapp-double-free-vulnerability/>

Rationale
	The specification of realloc(3) has been problematic since the
	very first standards, even before ISO C.  The wording has
	changed significantly, trying to forcedly permit implementations
	to return a null pointer when the requested size is zero.  This
	originated from the intent of banning zero-sized objects from
	the language in C89, but that never worked well in
	retrospective, as we can see from the fallout.

	None of the specifications have been good, and C23 finally gave
	up and made it undefined behavior.

	The problem is not only theoretical.  Programmers don't know how
	to use realloc(3) correctly, and have written weird code in
	their attempts.  This has resulted in a lot of non-sensical code
	in configure scripts[1], and even bugs in actual programs[2].

	[1] <https://codesearch.debian.net/search?q=%5Cbrealloc%5B+%5Ct%5D*%5B%28%5D%5B%5E%2C%5D*%2C%5B+%5Ct%5D0%5B%29%5D&literal=0>
	[2] <https://lore.kernel.org/lkml/20220213182443.4037039-1-keescook@chromium.org/>

	In some cases, this non-sensical code has resulted in RCEs[3].

	[3] <https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>

	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
	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.

	Code written for platforms returning a null pointer can be
	migrated to platforms returning non-null, without significant
	issues.

	There are two kinds of code that call realloc(p,0).  One
	hard-codes the 0, and is used as a replacement of free(p).  This
	code ignores the return value, since it's unimportant.  This
	code currently produces a leak of 0 bytes plus associated
	metadata on platforms such as musl libc, where it returns a
	non-null pointer.  However, assuming that there are programs
	written with the knowledge that they won't ever be run on such
	platforms, we should take care of that, and make sure they don't
	leak.  A way of accomplishing this would be to recommend
	implementations to issue a diagnostic when realloc(3) is called
	with a hardcoded zero.  This is only an informal recommendation
	made by this proposal, as this is a matter of QoI, and the
	standard shouldn't say anything about it.  This would prevent
	this class of minor leaks.

	Moreover, in glibc, realloc(p,0) may return non-null, in the
	case where p is NULL, so code must already take that into
	account, and thus code that simply takes realloc(p,0) as a
	synonym of free(p) is already leaky, as free(NULL) is a no-op,
	but realloc(NULL,0) allocates 0 bytes.

	The other kind of code is in algorithms that realloc(3) an
	arbitrary size, which might eventually be zero.  This gets more
	complex.

	Here's the code that should be written for AIX or glibc:

		errno = 0;
		new = realloc(old, size);
		if (new == NULL) {
			if (errno == ENOMEM)
				free(old);
			goto fail;
		}
		...
		free(new);

	Failing to check for ENOMEM in these platforms before freeing
	the old pointer would result in a double-free.  If the program
	decides to continue using the old pointer instead of freeing it,
	it would result in a use-after-free.

	In the platforms where realloc(p,0) returns non-null, such as
	the BSDs or musl libc, it is simpler to handle it:

		new = realloc(old, size);
		if (new == NULL) {  // errno is ENOMEM
			free(old);
			goto fail;
		}
		...
		free(new);

	Whenever the result is a null pointer, these platforms are
	reporting an ENOMEM error, and thus it is superfluous to check
	errno there.

	Most code is written in this way, even if run on platforms
	returning a null pointer.  This is because most programmers are
	just unaware of this problem.  Part of the reason is also that
	returning a non-null pointer with zero bytes is the natural
	extension of the behavior, which is what programmers intuitively
	expect from libc; that is, if realloc(p,3) allocates 3 bytes,
	r(p,2) allocates two bytes, and r(p,1) allocates one byte, it is
	natural by induction to expect that r(p,0) will allocate zero
	bytes.  Most algorithms naturally extend to 0 just fine, and
	special casing 0 is artificial.

	If the realloc(3) specification were changed to require that
	realloc(p,0) returns non-null on success, and that realloc(p,0)
	only fails when out-of-memory (and assuming the implementations
	will continue setting errno to ENOMEM), then code written for
	AIX or glibc would continue working just fine, since the errno
	check would be redundant with the null check.  Simply, the
	conditional (errno == ENOMEM) would always be true when
	(new == NULL).

	Then, there are non-POSIX platforms that don't set ENOMEM.  In
	those platforms, code might do this:

		new = realloc(old, size);
		if (new == NULL) {
			if (size != 0)
				free(old);
			goto fail;
		}
		...
		free(new);

	That code would continue working with this proposal, except for
	a very rare corner case, in which it would leak.  In the normal
	case, (size != 0) would never be true under (new == NULL),
	because a reallocation of 0 bytes would almost always succeed,
	and thus not return a null pointer under this proposal.
	However, in some cases, the system might not find space even for
	the small metadata needed for a 0-byte allocation.  In such
	case, the (size != 0) conditional would prevent deallocating
	'old', and thus cause a memory leak.  This case is exceptional
	enough that it shouldn't stop us from fixing realloc(3).
	Anyway, on an out-of-memory case, the program is likely to
	terminate rather soon, so the issue is even less likely to have
	an impact on any existing programs.  Also, LLVM's address
	sanitizer will soon able to catch such a leak:
	<https://github.com/llvm/llvm-project/issues/113065>

	This proposal makes handling of realloc(3) as straightforward as
	one would expect, with only two states: success or error.  There
	are no in-between states.

	The resulting wording in the standard is also much simpler, as
	it doesn't need to define so many special cases.

	For consistency, all the other allocation functions are updated
	to both return a null pointer on error, and use consistent
	wording.

Prior art
    gnulib
	gnulib provides the realloc-posix module, which aims to wrap the
	system realloc(3) and reallocarray(3) functions so that they
	behave in a POSIX-complying manner.

	It previously behaved like glibc.  After I reported that it was
	non-conforming to POSIX, we discussed the best way forward,
	which we agreed was the same direction that this paper is
	proposing now for C2y.  The implementation was changed in

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

	There have been no regression reports since then, as we
	expected.

    Unix V7, BSD
	The proposed behavior is the one endorsed by Doug McIlroy, the
	author of the original implementation of realloc(3) in Unix V7,
	and also present in the BSDs.

    glibc <= 2.1
	glibc was implemented originally to return non-null.  It was
	only in 1999, and purely to comply with the standards --with no
	requests by users to do so--, that the glibc maintainers decided
	to switch to the current behavior.

Design decisions
	This change needs two changes, which can be applied all at once,
	or in separate steps.

	The first step would make realloc(p,s) be consistent with
	free(p) and malloc(s), including when p is a null pointer, when
	s is zero, and also when both corner cases happen at the same
	time.  This change would already turn the implementations where
	malloc(0) returns non-null into the end goal we have.

	This first step would require changes to (at least) the
	following implementations: glibc, Bionic, Windows.

	The second step would be to require that malloc(0) returns a
	non-null pointer.

	The second step would require changes to (at least) the
	following implementations: AIX.

	This proposal has merged all steps into a single proposal.

Future directions
	This proposal, by specifying realloc(3) as-if by calling
	free(3) and malloc(3), makes redundant several mentions of
	realloc(3) next to either free(3) or malloc(3) in the standard.
	We could remove them in this proposal, or clean up that in a
	separate (mostly editorial) proposal.  Let's keep it for a
	future proposal for now.

Caveats
    n?n:1
	Code written today should be careful, in case it can run on
	older systems that are not fixed to comply with this stricter
	specification.  Thus, code written today should call realloc(3)
	similar to this:

		realloc(p, n?n:1);

	When all existing implementations are fixed to comply with this
	stricter specification, that workaround can be removed.

    ENOMEM
	Existing implementations that set errno to ENOMEM must continue
	doing so when the input pointer is not freed.  If they didn't,
	code that is currently portable to all POSIX systems

		errno = 0;
		new = realloc(old, size);
		if (new == NULL) {
			if (errno == ENOMEM)
				free(old);
			goto fail;
		}
		...
		free(new);

	would leak on error.

	Since it is currently impossible to write code today that is
	portable to arbitrary C17 systems, this is not an issue in
	ISO C.

		-  New code written for C2y will only need to check for
		   NULL to detect errors.

		-  Code written for specific C17 and older platforms
		   that don't set errno will continue to work for those
		   specific platforms.

		-  Code written for POSIX.1-2024 and older platforms
		   will continue working on POSIX C2y platforms,
		   assuming that POSIX will continue mandating ENOMEM.

		-  Code written for POSIX.1-2024 and older will not be
		   able to be run on non-POSIX C2y platforms, but that
		   could be expected.

	The only important thing is that platforms that did set ENOMEM
	should continue setting it, to avoid introducing leaks.

Proposed wording
	Based on N3550.

    7.25.4.1  Memory management functions :: General
	@@ p1
	...
	 If the size of the space requested is zero,
	-the behavior is implementation-defined:
	-either
	-a null pointer is returned to indicate the 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.

    7.25.4.2  The aligned_alloc function
	@@ Returns, p3
	 The <b>aligned_alloc</b> function returns
	-either
	-a null pointer
	-or
	-a pointer to the allocated space.
	+a pointer to the allocated space
	+on success.
	+If
	+the space cannot be allocated,
	+a null pointer is returned.

    7.25.4.3  The calloc function
	@@ Returns, p3
	 The <b>calloc</b> function returns
	-either
	 a pointer to the allocated space
	+on success.
	-or a null pointer
	-if
	+If
	 the space cannot be allocated
	 or if the product <tt>nmemb * size</tt>
	-would wraparound <b>size_t</b>.
	+would wraparound <b>size_t</b>,
	+a null pointer is returned.

    7.25.4.7  The malloc function
	@@ Returns, p3
	 The <b>malloc</b> function returns
	-either
	-a null pointer
	-or
	-a pointer to the allocated space.
	+a pointer to the allocated space
	+on success.
	+If
	+the space cannot be allocated,
	+a null pointer is returned.

    7.25.4.8  The realloc function
	@@ Description, p2
	 The <b>realloc</b> function
	 deallocates the old object pointed to by <tt>ptr</tt>
	+as if by a call to <b>free</b>,
	 and returns a pointer to a new object
	-that has the size specified by <tt>size</tt>.
	+that has the size specified by <tt>size</tt>
	+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.

	@@ 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.

	@@ Returns, p4
	 The <b>realloc</b> function returns
	 a pointer to the new object
	 (which can have the same value
	-as a pointer to the old object),
	+as a pointer to the old object)
	+on success.
	-or
	+If
	+space cannot be allocated,
	 a null pointer
	-if the new object has not been allocated.
	+is returned.

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: alx-0029r3 - Restore the traditional realloc(3) specification
       [not found]             ` <20250625001927.GP1827@brightrain.aerifal.cx>
@ 2025-06-25 14:10               ` enh
  0 siblings, 0 replies; 38+ messages in thread
From: enh @ 2025-06-25 14:10 UTC (permalink / raw)
  To: Rich Felker
  Cc: Jeffrey Walton, musl, Florian Weimer, libc-alpha, bug-gnulib,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Bruno Haible,
	JeanHeyd Meneide, Adhemerval Zanella Netto, Joseph Myers,
	Laurent Bercot, Andreas Schwab, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

On Tue, Jun 24, 2025 at 8:19 PM Rich Felker <dalias@libc.org> wrote:
>
> On Tue, Jun 24, 2025 at 08:14:32PM -0400, Jeffrey Walton wrote:
> > On Tue, Jun 24, 2025 at 10:18 AM Alejandro Colomar <alx@kernel.org> wrote:
> > >
> > > Hi Florian,
> > >
> > > On Tue, Jun 24, 2025 at 11:07:53AM +0200, Florian Weimer wrote:
> > > > [...]
> > > > Wouldn't it be more consistent to move in the other direction, and
> > > > require that allocations of zero size fail because C does not support
> > > > zero-sized objects?
> > >
> > > That's what some people have attempted since the times of SysV and C89.
> > > Three decades after, people haven't achieved that, and we see the
> > > fallout.
> > >
> > > Plus, the only direction in which moving is relatively safe is from
> > > returning-NULL behavior to returning-non-null behavior.  Consider this
> > > code written for a realloc(p,0) that returns NULL:
> > >
> > >         errno = 0;
> > >         new = realloc(old, n);
> > >         if (new == NULL) {
> > >                 if (errno == ENOMEM)
> > >                         free(old);
> > >                 goto fail;
> > >         }
> > >         ...
> > >         free(new);
> > >
> > > If you suddenly return non-null from realloc(p,0), that code will
> > > continue behaving well.  In some other cases, as you can see in my
> > > proposal, a memory leak would be introduced, which is a very mild
> > > problem.
> >
> > I don't think a small memory leak is always a mild problem. On
> > Android, it could [eventually] use up all device memory as shared
> > objects are unloaded/loaded during the lifetime of an activity. I know
> > OpenSSL used to give the Java folks a lot of problems because they
> > (OpenSSL) was not cleaning up memory during the unload.
>
> Isn't it normal/expected that Android apps leak memory all over the
> place, in significant amounts not malloc(0)'s, and that the system
> just keeps killing and restarting activities?

no. if the system has to do that, that's considered a negative app
quality signal.

this is like saying "aren't all linux apps expected to leak memory and
be killed by the OOM killer?". sure, you can do that, but expect to
hear complaints.

> Small memory leaks can be a problem, like if they were in pid 1 or
> something long-lived and critical, but that kind of software really
> should be well-audited/tested for this kind of bug. I don't think
> Android apps are one of the cases where it matters, though.
>
> Rich

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r4 - Restore the traditional realloc(3) specification
       [not found]           ` <yc3bptzhluejuxaawnjgwu234ii7dwmxsacmaa6tyrx2tslkc4@bw2dnt3rlgbl>
@ 2025-06-25 18:07             ` Wilco Dijkstra
  2025-06-25 18:20               ` Eric Blake
  2025-06-25 18:21               ` Alejandro Colomar
  0 siblings, 2 replies; 38+ messages in thread
From: Wilco Dijkstra @ 2025-06-25 18:07 UTC (permalink / raw)
  To: Alejandro Colomar, Eric Blake
  Cc: libc-alpha, Florian Weimer, bug-gnulib, musl,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Thorsten Glaser, Vincent Lefevre, Mark Harris,
	Collin Funk, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil

Hi Alejandro,

> > > >  +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"?

> Oh, the text is still there; I didn't see it.  :)

>        The realloc function returns a pointer to the new object
>        (which can have the same value as a pointer to the old object),
>        or a null pointer if the new object has not been allocated

In principle a realloc that shrinks a non-NULL block does never need to fail.
If it can't shrink the current block (either because internal design means it
can't make it any smaller or because it doesn't have memory for a new
smaller block) then it should preferably return the original pointer instead
of returning NULL and taking the failure path.

So I'm wondering whether we should more clearly specify this - whenever
it's possible to not fail, don't return NULL?

Cheers,
Wilco




^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r4 - Restore the traditional realloc(3) specification
  2025-06-25 18:07             ` [musl] " Wilco Dijkstra
@ 2025-06-25 18:20               ` Eric Blake
  2025-06-25 18:21               ` Alejandro Colomar
  1 sibling, 0 replies; 38+ messages in thread
From: Eric Blake @ 2025-06-25 18:20 UTC (permalink / raw)
  To: Wilco Dijkstra
  Cc: Alejandro Colomar, libc-alpha, Florian Weimer, bug-gnulib, musl,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Thorsten Glaser, Vincent Lefevre, Mark Harris,
	Collin Funk, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil

On Wed, Jun 25, 2025 at 06:07:06PM +0000, Wilco Dijkstra wrote:
> Hi Alejandro,
> 
> > > > >  +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"?
> 
> > Oh, the text is still there; I didn't see it.  :)
> 
> >        The realloc function returns a pointer to the new object
> >        (which can have the same value as a pointer to the old object),
> >        or a null pointer if the new object has not been allocated
> 
> In principle a realloc that shrinks a non-NULL block does never need to fail.
> If it can't shrink the current block (either because internal design means it
> can't make it any smaller or because it doesn't have memory for a new
> smaller block) then it should preferably return the original pointer instead
> of returning NULL and taking the failure path.
> 
> So I'm wondering whether we should more clearly specify this - whenever
> it's possible to not fail, don't return NULL?

Rich already made the strong argument that for an implementation that
encodes which arena a pointer was allocated from, shrinking in place
only works so long as the unused tail of the allocation does not
exceed a certain bound; and Alejandro removed the quote from Doug
McIlroy from an earlier version of the draft precisely because we do
NOT want the standard to mandate the inability to fail on shrinking an
object, as that will harm quality-of-implementation.

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


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r4 - Restore the traditional realloc(3) specification
  2025-06-25 18:07             ` [musl] " Wilco Dijkstra
  2025-06-25 18:20               ` Eric Blake
@ 2025-06-25 18:21               ` Alejandro Colomar
  1 sibling, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-25 18:21 UTC (permalink / raw)
  To: Wilco Dijkstra
  Cc: Eric Blake, libc-alpha, Florian Weimer, bug-gnulib, musl,
	наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Thorsten Glaser, Vincent Lefevre, Mark Harris,
	Collin Funk, DJ Delorie, Cristian Rodríguez,
	Siddhesh Poyarekar, Sam James, Mark Wielaard, Maciej W. Rozycki,
	Martin Uecker, Christopher Bazley, eskil

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

Hi Wilco,

On Wed, Jun 25, 2025 at 06:07:06PM +0000, Wilco Dijkstra wrote:
> In principle a realloc that shrinks a non-NULL block does never need to fail.
> If it can't shrink the current block (either because internal design means it
> can't make it any smaller or because it doesn't have memory for a new
> smaller block) then it should preferably return the original pointer instead
> of returning NULL and taking the failure path.
> 
> So I'm wondering whether we should more clearly specify this - whenever
> it's possible to not fail, don't return NULL?

As Rich Felker said, musl has very good reasons for failing, several of
them.  Look at his comments in the thread.


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r5 - Restore the traditional realloc(3) specification
       [not found]     ` <CAMdZqKGoCO6xmzq1=+Oa_xe4emeKRxY6FEaN3cY6mW6mUb6ggw@mail.gmail.com>
@ 2025-06-27  1:51       ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-27  1:51 UTC (permalink / raw)
  To: Mark Harris
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Thorsten Glaser, Eric Blake,
	Vincent Lefevre, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

[-- Attachment #1: Type: text/plain, Size: 30900 bytes --]

Hi Mark,

On Thu, Jun 26, 2025 at 05:44:49PM -0700, Mark Harris wrote:
> > Rationale
> >         The specification of realloc(3) has been problematic since the
> >         very first standards, even before ISO C.  The wording has
> >         changed significantly, trying to forcedly permit implementations
> >         to return a null pointer when the requested size is zero.  This
> >         originated from the intent of banning zero-sized objects from
> >         the language in C89, but that never worked well in
> >         retrospective, as we can see from the fallout.
> 
> I support the outcome that you are trying to achieve, however I think
> the proposal could use a better explanation upfront as to what problem
> this is attempting to solve.  Calling a well-established function like
> realloc "problematic" without explaining what is problematic about it
> isn't helpful.

If you go a few paragraphs below, you'll find that there have been RCE
vulnerabilities because people don't know how to use it correctly.
I've personally fixed many bugs in old calls to realloc(3) in projects
like shadow utils.

>  This states that the wording has changed
> significantly, but if that was the problem then a proposal to change
> the wording again is clearly not addressing that.

The problem was in trying to come up with a wording that accepted all
existing implementations, which isn't easy or even useful.

My proposal is not to attempt to reword the same thing, but rather
prohibit the weird implementations so that we remain with something
simple that can be worded without mistakes.

> Also I'm pretty sure that this did not originate from the intent of
> banning zero-sized objects from the language.  If there was an actual
> effort to ban the possibility of zero-sized objects then it would have
> been easier for them to simply define malloc(0) and realloc(p, 0) to
> always be an error.

They probably weren't brave enough to break the BSDs.  But I know there
was intention in the committee of removing zero-sized objects.

>  It seems far more likely that the committee was
> just trying to document the current behavior that programmers could
> rely on, without unnecessarily making current implementations
> nonconforming.
> 
> >
> >         None of the specifications have been good, and C23 finally gave
> >         up and made it undefined behavior.
> >
> >         The problem is not only theoretical.  Programmers don't know how
> >         to use realloc(3) correctly, and have written weird code in
> >         their attempts.  This has resulted in a lot of non-sensical code
> >         in configure scripts[1], and even bugs in actual programs[2].
> >
> >         [1] <https://codesearch.debian.net/search?q=%5Cbrealloc%5B+%5Ct%5D*%5B%28%5D%5B%5E%2C%5D*%2C%5B+%5Ct%5D0%5B%29%5D&literal=0>
> 
> It's not clear what you are claiming is nonsensical here or why.  You
> think that configure checks are in general nonsensical, or what is it
> about these checks in particular that is nonsensical?

I'm claiming that people write code that doesn't do what they think it
does, just because they know realloc(3) is broken and try to workaround
it.  Without going too far, here's the code I've seen in FreeBSD's
implementation of reallocf(3):

	$ grepc -htfd reallocf .
	void *
	reallocf(void *ptr, size_t size)
	{
		void *nptr;

		nptr = realloc(ptr, size);

		/*
		 * When the System V compatibility option (malloc "V" flag) is
		 * in effect, realloc(ptr, 0) frees the memory and returns NULL.
		 * So, to avoid double free, call free() only when size != 0.
		 * realloc(ptr, 0) can't fail when ptr != NULL.
		 */
		if (!nptr && ptr && size != 0)
			free(ptr);
		return (nptr);
	}

The last sentence in the comment is false, and this code has a memory
leak.  I'll leave it as an exercise to the reader to figure out why.
(Of course, I've already reported the bug, just a few days ago.)

> >         [2] <https://lore.kernel.org/lkml/20220213182443.4037039-1-keescook@chromium.org/>
> >
> >         In some cases, this non-sensical code has resulted in RCEs[3].
> >
> >         [3] <https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>
> 
> This is using reallocarray(), which comes from OpenBSD, and is not in
> ISO C at all.  In OpenBSD it already had the desired behavior for size
> 0; an implementation of the OpenBSD reallocarray() that does not
> correctly match its behavior is just buggy.  POSIX picked it up after
> Glibc and Bionic already created an implementation that did not match
> the OpenBSD behavior.

As you say, reallocarray(3) was later picked by glibc, where it was
implemented consistent with the realloc(3) in glibc, so both APIs have
inherently the same portability issues, and the only difference is in
the prevention of overflow in the multiplication.

Are you claiming that glibc has a buggy implementation of
reallocarray(3)?

	alx@debian:~/tmp$ cat ra.c 
	#include <stdio.h>
	#include <stdlib.h>

	int
	main(void)
	{
		printf("%p\n", reallocarray(malloc(1), 0, 42));
		perror("realloc");
	}
	alx@debian:~/tmp$ gcc ra.c 
	alx@debian:~/tmp$ ./a.out 
	(nil)
	realloc: Success

I certainly agree with you; glibc is buggy; please fix it.  On the other
hand, that has no effect on the matter:

People are confused about how to properly use realloc(3), and people
(correctly) assume reallocarray(3) ain't different, and thus they remain
confused about it too.

> >         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 uses an
> >         independent implemention rather than a Unix derivative-- also
> >         had this behavior originally; it changed to the current behavior
> >         in 1999 (glibc 2.1.1), only for compatibility with C89, even
> >         though ironically C99 was released soon after and removed the
> >         text that glibc was trying to comply to, and introduced some new
> >         text that was very confusing, and one of its interpretations
> >         would make the new glibc behavior non-conforming.
> 
> s/in range/in a range/
> s/implemention/implementation/
> s/comply to/comply with/

Thanks!

> Assuming that you are referring to Seventh Edition Unix from 1979, it
> would be better to spell it out or write V7 Unix, to distinguish it
> from UNIX V7 (https://unix.org/unixv7.html) which refers to Issue 7 of
> the standard commonly known as POSIX.

Agree.

> Your claim that this 1979 implementation of realloc()[1] "doesn't have
> any issues" is grossly incongruent with reality.  This realloc(p, n)
> first calls free(p), then malloc(n), and finally copies the data if
> the pointer has changed; at the time this was safe because there was
> no multithreading and free() and malloc() did not modify the contents
> of the memory block, however if realloc() failed it returned NULL with
> p freed (but you could still read the data from the freed block at
> least until the next allocation).

Hmm, yeah, I was aware of that, but my wording doesn't reflect it.  I
should rephrase as "didn't have any issues regarding the handling of
zero-sized objects".

>  Also this implementation of
> realloc() did not accept p == NULL; that would crash.  However, a
> documented bonus feature not found in modern realloc() was that p
> could be "a block freed since the last call of malloc, realloc or
> calloc".[2]

That's an issue of free(3) in reality.  If we say that the specification
of realloc(3) was to free(3) and malloc(3), then it's not realloc(3)'s
problem to say whether NULL is acceptable or not.

> [1] https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/libc/gen/malloc.c
> [2] https://man.cat-v.org/unix_7th/3/malloc
> 
> Is this really the "traditional realloc(3) specification" that the
> title of this proposal is suggesting be restored?  I suggest being
> more specific as to what you actually want.

Regarding zero-sized objects, yes.  I guess what I want is the BSD
specification, which is the traditional one, but with the unrelated bugs
fixed, and a better free(3) that accepts NULL, which results in a
realloc(3) that accepts NULL.  See the proposed wording, which just
defers to the specification of free(3).

> >         Code written for platforms returning a null pointer can be
> >         migrated to platforms returning non-null, without significant
> >         issues.
> >
> >         There are two kinds of code that call realloc(p,0).  One
> >         hard-codes the 0, and is used as a replacement of free(p).  This
> >         code ignores the return value, since it's unimportant.  This
> >         code currently produces a leak of 0 bytes plus associated
> >         metadata on platforms such as musl libc, where it returns a
> >         non-null pointer.  However, assuming that there are programs
> >         written with the knowledge that they won't ever be run on such
> >         platforms, we should take care of that, and make sure they don't
> >         leak.  A way of accomplishing this would be to recommend
> >         implementations to issue a diagnostic when realloc(3) is called
> >         with a hardcoded zero.  This is only an informal recommendation
> >         made by this proposal, as this is a matter of QoI, and the
> >         standard shouldn't say anything about it.  This would prevent
> >         this class of minor leaks.
> 
> It used to be a common thing for a C library or function to allow
> overriding the allocator that it uses internally with your own custom
> allocator.  Rather than having to specify multiple function pointers
> for your own custom malloc, free, realloc, etc. sometimes it would
> just take one function pointer for your custom realloc, with the
> default being libc realloc.  The library would allocate memory using
> (*customalloc)(NULL, n), free it using (*customalloc)(p, 0), and
> realloc using (*customalloc)(p, n).  This simplified the interface for
> overriding the allocator, and if it stored the custom allocator in
> each object then it only had to store one function pointer.  The point
> is that I would expect calls to realloc that intend to only free
> memory are more likely to be indirect calls than direct calls that are
> easily diagnosed at compile time or with a simple search; for a direct
> call it is easier to just call free.  That said, I haven't seen this
> kind of interface for years.

Good.  For the few cases that may exist today, I guess they'll have
minor leaks of 0 bytes.  I can live with that.

> Both Glibc and Bionic already annotate realloc with
> __attribute__((__warn_unused_result__)), so that should already warn
> about direct calls to realloc(p, 0) that don't use the result
> (indicating that the caller was likely intending to only free the
> memory and not get another block in return).  I would consider that
> existing warning to be better than warning on any realloc(p, 0),
> because it avoids false positives when the caller is already handling
> any pointer that may be returned.

This is not enough.  There are programs that call

	p = realloc(p, 0);

as a compact spelling of

	free(p);
	p = NULL;

In such code, the attribute wouldn't trigger a diagnostic.  Not that I
care much though.  As I said, such a minor leak shouldn't be important.
But I mention that for completeness.  Also, GCC maintainers seem in
favour of the diagnostic, even if just because C23 made it UB and thus
a diagnostic is needed, regardless of the outcome of this proposal.

> >         Moreover, in glibc, realloc(p,0) may return non-null, in the
> >         case where p is NULL, so code must already take that into
> >         account, and thus code that simply takes realloc(p,0) as a
> >         synonym of free(p) is already leaky, as free(NULL) is a no-op,
> >         but realloc(NULL,0) allocates 0 bytes.
> >
> >         The other kind of code is in algorithms that realloc(3) an
> >         arbitrary size, which might eventually be zero.  This gets more
> >         complex.
> >
> >         Here's the code that should be written for AIX or glibc:
> >
> >                 errno = 0;
> >                 new = realloc(old, size);
> >                 if (new == NULL) {
> >                         if (errno == ENOMEM)
> >                                 free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> 
> That is ridiculous; I've never seen anyone else check errno to
> determine whether realloc has failed.  It is far easier to just ensure
> that size is non-zero.  Yes it would be even easier if you didn't need
> to ensure that, which is why I support your proposal, but it doesn't
> have anything to do with errno.

I had to take into account the most unreasonable cases, to make sure no
issues are possible.  Of course, one can call realloc(p,n?:1) --which
I do--, or even not call it in the first place.  But in those cases,
we don't even care about it.  It's not my problem.  I only need to care
about those calling it with a size that might be zero.

Some people were irrationally claiming that my proposal would result in
double-free and use-after-free bugs, so I had to take every possible
code people could write around realloc(3) and consider what would
happen if we changed the behavior.

And also, remember that FreeBSD wrote this:

	$ grepc -htfd reallocf .
	void *
	reallocf(void *ptr, size_t size)
	{
		void *nptr;

		nptr = realloc(ptr, size);

		/*
		 * When the System V compatibility option (malloc "V" flag) is
		 * in effect, realloc(ptr, 0) frees the memory and returns NULL.
		 * So, to avoid double free, call free() only when size != 0.
		 * realloc(ptr, 0) can't fail when ptr != NULL.
		 */
		if (!nptr && ptr && size != 0)
			free(ptr);
		return (nptr);
	}

It doesn't check errno, but it does try to recover post-morten from a
terrible situation.  Indeed, it should have checked errno to prevent the
leak.  Or it could have done realloc(p,n?:1) and call it a day.

[...]

> >         Failing to check for ENOMEM in these platforms before freeing
> >         the old pointer would result in a double-free.  If the program
> >         decides to continue using the old pointer instead of freeing it,
> >         it would result in a use-after-free.
> >
> >         In the platforms where realloc(p,0) returns non-null, such as
> >         the BSDs or musl libc, it is simpler to handle it:
> >
> >                 new = realloc(old, size);
> >                 if (new == NULL) {  // errno is ENOMEM
> >                         free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         Whenever the result is a null pointer, these platforms are
> >         reporting an ENOMEM error, and thus it is superfluous to check
> >         errno there.
> >
> >         Most code is written in this way, even if run on platforms
> >         returning a null pointer.  This is because most programmers are
> >         just unaware of this problem.  Part of the reason is also that
> >         returning a non-null pointer with zero bytes is the natural
> >         extension of the behavior, which is what programmers intuitively
> >         expect from libc; that is, if realloc(p,3) allocates 3 bytes,
> >         r(p,2) allocates two bytes, and r(p,1) allocates one byte, it is
> >         natural by induction to expect that r(p,0) will allocate zero
> >         bytes.  Most algorithms naturally extend to 0 just fine, and
> >         special casing 0 is artificial.
> >
> >         If the realloc(3) specification were changed to require that
> >         realloc(p,0) returns non-null on success, and that realloc(p,0)
> >         only fails when out-of-memory (and assuming the implementations
> >         will continue setting errno to ENOMEM), then code written for
> >         AIX or glibc would continue working just fine, since the errno
> >         check would be redundant with the null check.  Simply, the
> >         conditional (errno == ENOMEM) would always be true when
> >         (new == NULL).
> >
> >         Then, there are non-POSIX platforms that don't set ENOMEM.  In
> >         those platforms, code might do this:
> >
> >                 new = realloc(old, size);
> >                 if (new == NULL) {
> >                         if (size != 0)
> >                                 free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         That code would continue working with this proposal, except for
> >         a very rare corner case, in which it would leak.  In the normal
> >         case, (size != 0) would never be true under (new == NULL),
> 
> This is backwards.
> s/never // ?

Nope.  It is correct.  Maybe I should append to the sentence to clarify:

	In the normal case, (size != 0) would never be true under
	(new == NULL) after this proposed change.

> >         because a reallocation of 0 bytes would almost always succeed,
> >         and thus not return a null pointer under this proposal.
> >         However, in some cases, the system might not find space even for
> >         the small metadata needed for a 0-byte allocation.  In such
> >         case, the (size != 0) conditional would prevent deallocating
> >         'old', and thus cause a memory leak.  This case is exceptional
> >         enough that it shouldn't stop us from fixing realloc(3).
> >         Anyway, on an out-of-memory case, the program is likely to
> >         terminate rather soon, so the issue is even less likely to have
> >         an impact on any existing programs.  Also, LLVM's address
> >         sanitizer will soon able to catch such a leak:
> >         <https://github.com/llvm/llvm-project/issues/113065>
> >
> >         This proposal makes handling of realloc(3) as straightforward as
> >         one would expect, with only two states: success or error.  There
> >         are no in-between states.
> >
> >         The resulting wording in the standard is also much simpler, as
> >         it doesn't need to define so many special cases.
> >
> >         For consistency, all the other allocation functions are updated
> >         to both return a null pointer on error, and use consistent
> >         wording.
> >
> >     Why not go the other way around?
> >         Some people keep asking why not go the other way around: why not
> >         force the BSDs and musl to return a null pointer if size is 0.
> >         This would result in double-free and use-after-free bugs, which
> >         can result in RCE vulnerabilities (remote code execution), which
> >         is clearly unacceptable.
> >
> >         Consider this code, which is the usual code for calling
> >         realloc(3) in such systems:
> >
> >                 new = realloc(old, size);
> >                 if (new == NULL) {
> >                         free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         If realoc(p,0) would return a null pointer and free the old
> 
> s/realoc/realloc/

Thanks!

> >         block, then the third line would be a double-free bug.
> >
> > Prior art
> >     gnulib
> >         gnulib provides the realloc-posix module, which aims to wrap the
> >         system realloc(3) and reallocarray(3) functions so that they
> >         behave in a POSIX-complying manner.
> >
> >         It previously behaved like glibc.  After I reported that it was
> >         non-conforming to POSIX, we discussed the best way forward,
> >         which we agreed was the same direction that this paper is
> >         proposing now for C2y.  The implementation was changed in
> >
> >                 gnulib.git d884e6fc4a60 (2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
> >
> >         There have been no regression reports since then, as we
> >         expected.
> >
> >     Unix V7, BSD
> 
> s/Unix V7/Seventh Edition Unix/

Thanks!

> >         The proposed behavior is the one endorsed by Doug McIlroy, the
> >         author of the original implementation of realloc(3) in Unix V7,
> >         and also present in the BSDs.
> >
> >     glibc <= 2.1
> >         glibc was implemented originally to return non-null.  It was
> >         only in 1999, and purely to comply with the standards --with no
> >         requests by users to do so--, that the glibc maintainers decided
> >         to switch to the current behavior.
> >
> > Design decisions
> >         This change needs two changes, which can be applied all at once,
> >         or in separate steps.
> >
> >         The first step would make realloc(p,s) be consistent with
> >         free(p) and malloc(s), including when p is a null pointer, when
> >         s is zero, and also when both corner cases happen at the same
> >         time.  This change would already turn the implementations where
> >         malloc(0) returns non-null into the end goal we have.  This
> >         would require changes to (at least) the following
> >         implementations: glibc, Bionic, Windows.
> >
> >         The second step would be to require that malloc(0) returns a
> >         non-null pointer.  This would require changes to (at least) the
> >         following implementations: AIX.
> 
> I appreciate that you no longer claim that these are the ONLY
> implementations that would require changes.

As far as libc is concerned, and especially for the first change, I'm
quite sure those are the only three.  I'm purposefully not considering
interposed implementations, though; only libc.  But yeah, this is
probably easier to state without wording mistakes.

> >
> >         This proposal has merged all steps into a single proposal.
> >
> > Future directions
> >         This proposal, by specifying realloc(3) as-if by calling
> >         free(3) and malloc(3), makes redundant several mentions of
> >         realloc(3) next to either free(3) or malloc(3) in the standard.
> >         We could remove them in this proposal, or clean up that in a
> >         separate (mostly editorial) proposal.  Let's keep it for a
> >         future proposal for now.
> >
> > Caveats
> >     n?n:1
> >         Code written today should be careful, in case it can run on
> >         older systems that are not fixed to comply with this stricter
> >         specification.  Thus, code written today should call realloc(3)
> >         similar to this:
> >
> >                 realloc(p, n?n:1);
> >
> >         When all existing implementations are fixed to comply with this
> >         stricter specification, that workaround can be removed.
> >
> >     ENOMEM
> >         Existing implementations that set errno to ENOMEM must continue
> >         doing so when the input pointer is not freed.  If they didn't,
> >         code that is currently portable to all POSIX systems
> >
> >                 errno = 0;
> >                 new = realloc(old, size);
> >                 if (new == NULL) {
> >                         if (errno == ENOMEM)
> >                                 free(old);
> >                         goto fail;
> >                 }
> >                 ...
> >                 free(new);
> >
> >         would leak on error.
> >
> >         Since it is currently impossible to write code today that is
> >         portable to arbitrary C17 systems, this is not an issue in
> >         ISO C.
> 
> Current code that calls realloc in a manner that is portable to
> arbitrary C17 or C23 systems will already ensure that the size
> argument is non-zero (for example, using the n?n:1 method above).
> Such code is very possible and requires no changes.

Again, I'm only concerned about code that calls realloc(p,n) where n
might be zero.  If it can't be zero, it's not my problem.  It is not
possible to call realloc(p,0) in a manner that is portable to C17
without leaking (or worse, DF or UAF).

As you've seen above, FreeBSD does this.  At least, they are only
concerned about POSIX, so they could have written it without a leak.
However, they wrote it in the C17-portable manner, which resulted in
a leak.  Why?  Because both standards have been confusing people about
realloc(3) for a long time.

> >                 -  New code written for C2y will only need to check for
> >                    NULL to detect errors.
> >
> >                 -  Code written for specific C17 and older platforms
> >                    that don't set errno will continue to work for those
> >                    specific platforms.
> >
> >                 -  Code written for POSIX.1-2024 and older platforms
> >                    will continue working on POSIX C2y platforms,
> >                    assuming that POSIX will continue mandating ENOMEM.
> >
> >                 -  Code written for POSIX.1-2024 and older will not be
> >                    able to be run on non-POSIX C2y platforms, but that
> >                    could be expected.
> 
> I don't see how this is relevant to this proposal.

I want to be comprehensive.  The C Committee is also concerned about
POSIX, since they have attepted to coordinated changes to realloc(3) in
the past, even if it didn't work well.  In fact, this time it better is
well coordinated, or we rather not do it at all.

> >         The only important thing is that platforms that did set ENOMEM
> >         should continue setting it, to avoid introducing leaks.
> >
> > Proposed wording
> >         Based on N3550.
> >
> >     7.25.4.1  Memory management functions :: General
> >         @@ p1
> >         ...
> >          If the size of the space requested is zero,
> >         -the behavior is implementation-defined:
> >         -either
> >         -a null pointer is returned to indicate the 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.
> >
> >     7.25.4.2  The aligned_alloc function
> >         @@ Returns, p3
> >          The <b>aligned_alloc</b> function returns
> >         -either
> >         -a null pointer
> >         -or
> >         -a pointer to the allocated space.
> >         +a pointer to the allocated space
> >         +on success.
> >         +If
> >         +the space cannot be allocated,
> >         +a null pointer is returned.
> >
> >     7.25.4.3  The calloc function
> >         @@ Returns, p3
> >          The <b>calloc</b> function returns
> >         -either
> >          a pointer to the allocated space
> >         +on success.
> >         -or a null pointer
> >         -if
> >         +If
> >          the space cannot be allocated
> >          or if the product <tt>nmemb * size</tt>
> >         -would wraparound <b>size_t</b>.
> >         +would wraparound <b>size_t</b>,
> >         +a null pointer is returned.
> >
> >     7.25.4.7  The malloc function
> >         @@ Returns, p3
> >          The <b>malloc</b> function returns
> >         -either
> >         -a null pointer
> >         -or
> >         -a pointer to the allocated space.
> >         +a pointer to the allocated space
> >         +on success.
> >         +If
> >         +the space cannot be allocated,
> >         +a null pointer is returned.
> >
> >     7.25.4.8  The realloc function
> >         @@ Description, p2
> >          The <b>realloc</b> function
> >          deallocates the old object pointed to by <tt>ptr</tt>
> >         +as if by a call to <b>free</b>,
> >          and returns a pointer to a new object
> >         -that has the size specified by <tt>size</tt>.
> >         +that has the size specified by <tt>size</tt>
> >         +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.
> >
> >         @@ 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
> >         +or return a different pointer
> >         +for a call that shrinks the block of memory.
> >
> >         @@ Returns, p4
> >          The <b>realloc</b> function returns
> >          a pointer to the new object
> >          (which can have the same value
> >         -as a pointer to the old object),
> >         +as a pointer to the old object)
> >         +on success.
> >         -or
> >         +If
> >         +space cannot be allocated,
> >          a null pointer
> >         -if the new object has not been allocated.
> >         +is returned.
> >
> 
> The actual changes seem quite reasonable, for those that make it this far.

Thanks!


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r5 - Restore the traditional realloc(3) specification
       [not found]   ` <ttmksxnr4ojqqkereep5j5vkakz5wg5e24mjvbllj6u5ibvn5k@e7jslgr5dt2b>
       [not found]     ` <CAMdZqKGoCO6xmzq1=+Oa_xe4emeKRxY6FEaN3cY6mW6mUb6ggw@mail.gmail.com>
@ 2025-06-27  8:52     ` Florian Weimer
  2025-06-27 13:26       ` Alejandro Colomar
  1 sibling, 1 reply; 38+ messages in thread
From: Florian Weimer @ 2025-06-27  8:52 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Thorsten Glaser, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

* Alejandro Colomar:

> It would be good to have explicit replies by glibc maintainers about it,
> so that the C Committee understands better what the maintainers think
> about it.  I've got word from some committee members that if I can
> convince the maintainers, they'll vote for standardizing it.  So, it
> would be great it people could emit 'Acked-by:' tags, or otherwise
> explain their position.

This is not how ISO standardization works.  In the end, it comes down to
how the national bodies vote.

I think the proposal is not clear about its intent.  It looks to me you
are trying to accomplish at least the following things:

  * all allocation functions can be used to allocate zero-sized objects
  * calloc, reallocarray can be used to allocate arbitrary large arrays
    of zero-sized objects
  * calloc, reallocarray  can be used to allocate zero-length arrays
    of arbitrarily-sized objects
  * realloc, reallocarray can no longer be used to deallocate storage

If you frame your proposal in terms of aligning with traditional
behavior, you are inviting a discussion what the traditional behavior
is.  But this doesn't really matter.

I'm not sure if your changes to the calloc, reallocarray are sufficient
text.  I assume we want full symmetry of the arguments because the
argument order in existing programs is not very consistent.  This
requires dropping the requirement that one of the arguments is an object
size (which rules out zero as a valid argument value).

From an implementation perspective, we need clarification that the
allocation functions (except aligned_alloc) may reduce the alignment of
the returned pointer to a power of two greater or equal to the requested
size, for allocation sizes that are less than the fundamental alignment.
(Some existing implementations already do this today, in violation of
the standard.)

Thanks,
Florian


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r5 - Restore the traditional realloc(3) specification
  2025-06-27  8:52     ` Florian Weimer
@ 2025-06-27 13:26       ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-27 13:26 UTC (permalink / raw)
  To: Florian Weimer
  Cc: libc-alpha, bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Laurent Bercot,
	Andreas Schwab, Thorsten Glaser, Eric Blake, Vincent Lefevre,
	Mark Harris, Collin Funk, Wilco Dijkstra, DJ Delorie,
	Cristian Rodríguez, Siddhesh Poyarekar, Sam James,
	Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

[-- Attachment #1: Type: text/plain, Size: 3953 bytes --]

Hi Florian,

On Fri, Jun 27, 2025 at 10:52:02AM +0200, Florian Weimer wrote:
> * Alejandro Colomar:
> 
> > It would be good to have explicit replies by glibc maintainers about it,
> > so that the C Committee understands better what the maintainers think
> > about it.  I've got word from some committee members that if I can
> > convince the maintainers, they'll vote for standardizing it.  So, it
> > would be great it people could emit 'Acked-by:' tags, or otherwise
> > explain their position.
> 
> This is not how ISO standardization works.

I'm member of the C Committee; I know how it works.

>  In the end, it comes down to
> how the national bodies vote.

It comes down to this:

-  I present a proposal (which I've already submitted; soon it will
   appear in the document log).
   <https://www.open-std.org/jtc1/sc22/wg14/www/wg14_document_log>

-  The proposal is voted by the committee members in the next meeting
   (that is, in two months, most likely).  If it's approved, it is put
   into the working draft.

-  Close to release of C2y, National Bodies may issue comments opposing
   the draft.  This is unlikely to change things meaningfully, if the
   previous step had strong consensus.

> I think the proposal is not clear about its intent.  It looks to me you
> are trying to accomplish at least the following things:
> 
>   * all allocation functions can be used to allocate zero-sized objects
>   * calloc, reallocarray can be used to allocate arbitrary large arrays
>     of zero-sized objects
>   * calloc, reallocarray  can be used to allocate zero-length arrays
>     of arbitrarily-sized objects
>   * realloc, reallocarray can no longer be used to deallocate storage

Yes, that's correct.  That's how they behave in musl and the BSDs (and
for calloc(3), in glibc too).

BTW, reallocarray(3) is not in ISO C (yet).

> If you frame your proposal in terms of aligning with traditional
> behavior, you are inviting a discussion what the traditional behavior
> is.  But this doesn't really matter.
> 
> I'm not sure if your changes to the calloc, reallocarray are sufficient
> text.  I assume we want full symmetry of the arguments because the
> argument order in existing programs is not very consistent.  This
> requires dropping the requirement that one of the arguments is an object
> size (which rules out zero as a valid argument value).

No, that doesn't rule it out.  calloc(3) is implemented in the BSDs,
musl, and glibc, that way, and it is conforming to ISO C (I think nobody
disputes that).  The relevant text in the standard is this:

    7.25.4.1  Memory management functions :: General
	@@ p1
	...
	 If the size of the space requested is zero,
	-the behavior is implementation-defined:
	-either
	-a null pointer is returned to indicate the 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.

That paragraph talks about the total size, not the size of each object.
If you read calloc(3), "the space" refers to the entire space, while
each object within the array is referred to as "each object".  So, this
paragraph, which says what happens when the total size is zero, doesn't
care if it's due to 'n' being 0 or 'size' being 0.

> From an implementation perspective, we need clarification that the
> allocation functions (except aligned_alloc) may reduce the alignment of
> the returned pointer to a power of two greater or equal to the requested
> size, for allocation sizes that are less than the fundamental alignment.

I think I shouldn't include that in my proposal, as it's not necessary,
and may hinder it's approval.

> (Some existing implementations already do this today, in violation of
> the standard.)

Feel free to propose such a change.


Have a llovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [musl] Re: alx-0029r6 - Restore the traditional realloc(3) specification
       [not found]   ` <vl4fdi3ohhclxsgjhzz27owlxl7dh3gnjslykaiphwta6f66cc@alqxmrejng53>
@ 2025-06-30  2:27     ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-06-30  2:27 UTC (permalink / raw)
  To: libc-alpha
  Cc: bug-gnulib, musl, наб,
	Douglas McIlroy, Paul Eggert, Robert Seacord, Elliott Hughes,
	Bruno Haible, JeanHeyd Meneide, Rich Felker,
	Adhemerval Zanella Netto, Joseph Myers, Florian Weimer,
	Laurent Bercot, Andreas Schwab, Thorsten Glaser, Eric Blake,
	Vincent Lefevre, Mark Harris, Collin Funk, Wilco Dijkstra,
	DJ Delorie, Cristian Rodríguez, Siddhesh Poyarekar,
	Sam James, Mark Wielaard, Maciej W. Rozycki, Martin Uecker,
	Christopher Bazley, eskil, Daniel Krügler, Kees Cook,
	Valdis Klētnieks

[-- Attachment #1: Type: text/plain, Size: 21138 bytes --]

Hi all,

This paper is now submitted to the C Commitee:
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3621.txt>

Have a lovely day!
Alex

On Fri, Jun 27, 2025 at 04:01:54PM +0200, Alejandro Colomar wrote:
> Hi!
> 
> Here's a new revision of the proposal, addressing some points raised by
> Mark, plus clarifying that the paragraph about when size is zero refers
> to the total size, as Florian was concerned that it might not be
> symmetric.
> 
> 
> Have a lovely day!
> Alex
> 
> ---
> Name
> 	alx-0029r6 - Restore the traditional realloc(3) specification
> 
> Principles
> 	-  Uphold the character of the language
> 	-  Keep the language small and simple
> 	-  Facilitate portability
> 	-  Avoid ambiguities
> 	-  Pay attention to performance
> 	-  Codify existing practice to address evident deficiencies.
> 	-  Do not prefer any implementation over others
> 	-  Ease migration to newer language editions
> 	-  Avoid quiet changes
> 	-  Enable secure programming
> 
> Category
> 	Remove UB.
> 
> Author
> 	Alejandro Colomar <alx@kernel.org>
> 
> 	Cc: <bug-gnulib@gnu.org>
> 	Cc: <musl@lists.openwall.com>
> 	Cc: <libc-alpha@sourceware.org>
> 	Cc: наб <nabijaczleweli@nabijaczleweli.xyz>
> 	Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
> 	Cc: Paul Eggert <eggert@cs.ucla.edu>
> 	Cc: Robert Seacord <rcseacord@gmail.com>
> 	Cc: Elliott Hughes <enh@google.com>
> 	Cc: Bruno Haible <bruno@clisp.org>
> 	Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
> 	Cc: Rich Felker <dalias@libc.org>
> 	Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
> 	Cc: Joseph Myers <josmyers@redhat.com>
> 	Cc: Florian Weimer <fweimer@redhat.com>
> 	Cc: Andreas Schwab <schwab@suse.de>
> 	Cc: Thorsten Glaser <tg@mirbsd.de>
> 	Cc: Eric Blake <eblake@redhat.com>
> 	Cc: Vincent Lefevre <vincent@vinc17.net>
> 	Cc: Mark Harris <mark.hsj@gmail.com>
> 	Cc: Collin Funk <collin.funk1@gmail.com>
> 	Cc: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
> 	Cc: DJ Delorie <dj@redhat.com>
> 	Cc: Cristian Rodríguez <cristian@rodriguez.im>
> 	Cc: Siddhesh Poyarekar <siddhesh@gotplt.org>
> 	Cc: Sam James <sam@gentoo.org>
> 	Cc: Mark Wielaard <mark@klomp.org>
> 	Cc: "Maciej W. Rozycki" <macro@redhat.com>
> 	Cc: Martin Uecker <ma.uecker@gmail.com>
> 	Cc: Christopher Bazley <chris.bazley.wg14@gmail.com>
> 	Cc: <eskil@obsession.se>
> 	Cc: Daniel Krügler <daniel.kruegler@googlemail.com>
> 	Cc: Kees Cook <keescook@chromium.org>
> 	Cc: Valdis Klētnieks <valdis.kletnieks@vt.edu>
> 
> History
> 	<https://www.alejandro-colomar.es/src/alx/alx/wg14/alx-0029.git/>
> 
> 	r0 (2025-06-17):
> 	-  Initial draft.
> 
> 	r1 (2025-06-20):
> 	-  Full rewrite after the recent glibc discussion.
> 
> 	r2 (2025-06-21):
> 	-  Remove CC.  Add CC.
> 	-  wfix.
> 	-  Drop quote.
> 	-  Add a few more principles
> 	-  Clarify why ENOMEM is used in this proposal, and make it
> 	   optional.
> 	-  Mention exceptional leak in code checking (size != 0).
> 	-  Clarify that part of the description of realloc can be
> 	   editorially removed after this change.
> 
> 	r3 (2025-06-23):
> 	-  Fix diff missing line.
> 	-  Remove ENOMEM from the proposal.
> 	-  Clarify that ENOMEM should be retained by platforms already
> 	   using it.
> 	-  Add mention that LLVM's address sanitizer will catch the leak
> 	   mentioned in r2.
> 	-  Add links to real bugs (including an RCE bug).
> 
> 	r4 (2025-06-24):
> 	-  Use a better link for the Whatsapp RCE.
> 	-  s/Description/Rationale/
> 	-  wfix
> 	-  Mention that glibc <2.1.1 had the BSD behavior.
> 	-  Add footnote that realloc(3) may fail while shrinking.
> 
> 	r5 (2025-06-26):
> 	-  It was glibc 2.1.1 that broke it, not glibc 2.2.
> 	-  wfix
> 	-  Mention in the footnote that the pointer may change.
> 	-  Document why not go the other way around.  It was explained
> 	   several times during discussion, but people keep suggesting
> 	   it.
> 
> 	r6 (2025-06-27):
> 	-  Clarify that the paragraph about what happens when the size
> 	   is zero refers to when the total size is zero (for calloc(3)
> 	   that is nmemb*size).
> 	-  s/Unix V7/V7 Unix/
> 	-  tfix.
> 	-  wfix.
> 
> See also
> 	<https://nabijaczleweli.xyz/content/blogn_t/017-malloc0.html>
> 	<https://sourceware.org/pipermail/libc-alpha/1999-April/000956.html>
> 	<https://inbox.sourceware.org/libc-alpha/20241019014002.3684656-1-siddhesh@sourceware.org/T/#u>
> 	<https://inbox.sourceware.org/libc-alpha/qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv/T/#u>
> 	<https://github.com/bminor/glibc/commit/7c2b945e1fd64e0a5a4dbd6ae6592a7314dcd4b5>
> 	<https://github.com/llvm/llvm-project/issues/113065>
> 	<https://www.austingroupbugs.net/view.php?id=400>
> 	<https://www.austingroupbugs.net/view.php?id=526>
> 	<https://www.austingroupbugs.net/view.php?id=688>
> 	<https://sourceware.org/bugzilla/show_bug.cgi?id=12547>
> 	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm>
> 	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n868.htm>
> 	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2438.htm>
> 	<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf>
> 	<https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/realloc.html>
> 	<https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/functions/realloc.html>
> 	<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120744>
> 	<https://lore.kernel.org/lkml/20220213182443.4037039-1-keescook@chromium.org/>
> 	<https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>
> 	<https://gbhackers.com/whatsapp-double-free-vulnerability/>
> 
> Rationale
> 	The specification of realloc(3) has been problematic since the
> 	very first standards, even before ISO C.  The wording has
> 	changed significantly, trying to forcedly permit implementations
> 	to return a null pointer when the requested size is zero.  This
> 	originated from the intent of banning zero-sized objects from
> 	the language in C89, but that never worked well in
> 	retrospective, as we can see from the fallout.
> 
> 	None of the specifications have been good, and C23 finally gave
> 	up and made it undefined behavior.
> 
> 	The problem is not only theoretical.  Programmers don't know how
> 	to use realloc(3) correctly, and have written weird code in
> 	their attempts.  This has resulted in a lot of non-sensical code
> 	in configure scripts[1], and even bugs in actual programs[2].
> 
> 	[1] <https://codesearch.debian.net/search?q=%5Cbrealloc%5B+%5Ct%5D*%5B%28%5D%5B%5E%2C%5D*%2C%5B+%5Ct%5D0%5B%29%5D&literal=0>
> 	[2] <https://lore.kernel.org/lkml/20220213182443.4037039-1-keescook@chromium.org/>
> 
> 	In some cases, this non-sensical code has resulted in RCEs[3].
> 
> 	[3] <https://awakened1712.github.io/hacking/hacking-whatsapp-gif-rce/>
> 
> 	However, this doesn't need to be like that.  The traditional
> 	implementation of realloc(3), present in V7 Unix, inherited by
> 	the BSDs, and currently available in a range of systems,
> 	including musl libc, doesn't have any issues regarding zero-size
> 	allocations.  glibc --which uses an independent implementation
> 	rather than a Unix derivative-- also had this behavior
> 	originally; it changed to the current behavior in 1999
> 	(glibc 2.1.1), only for compatibility with C89, even though
> 	ironically C99 was released soon after and removed the text that
> 	glibc was trying to comply with, and introduced some new text
> 	that was very confusing, and one of its interpretations would
> 	make the new glibc behavior non-conforming.
> 
> 	Code written for platforms returning a null pointer can be
> 	migrated to platforms returning non-null, without significant
> 	issues.
> 
> 	There are two kinds of code that call realloc(p,0).  One
> 	hard-codes the 0, and is used as a replacement of free(p).  This
> 	code ignores the return value, since it's unimportant.  This
> 	code currently produces a leak of 0 bytes plus associated
> 	metadata on platforms such as musl libc, where it returns a
> 	non-null pointer.  However, assuming that there are programs
> 	written with the knowledge that they won't ever be run on such
> 	platforms, we should take care of that, and make sure they don't
> 	leak.  A way of accomplishing this would be to recommend
> 	implementations to issue a diagnostic when realloc(3) is called
> 	with a hardcoded zero.  This is only an informal recommendation
> 	made by this proposal, as this is a matter of QoI, and the
> 	standard shouldn't say anything about it.  This would prevent
> 	this class of minor leaks.
> 
> 	Moreover, in glibc, realloc(p,0) may return non-null, in the
> 	case where p is NULL, so code must already take that into
> 	account, and thus code that simply takes realloc(p,0) as a
> 	synonym of free(p) is already leaky, as free(NULL) is a no-op,
> 	but realloc(NULL,0) allocates 0 bytes.
> 
> 	The other kind of code is in algorithms that realloc(3) an
> 	arbitrary size, which might eventually be zero.  This gets more
> 	complex.
> 
> 	Here's the code that should be written for AIX or glibc:
> 
> 		errno = 0;
> 		new = realloc(old, size);
> 		if (new == NULL) {
> 			if (errno == ENOMEM)
> 				free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	Failing to check for ENOMEM in these platforms before freeing
> 	the old pointer would result in a double-free.  If the program
> 	decides to continue using the old pointer instead of freeing it,
> 	it would result in a use-after-free.
> 
> 	In the platforms where realloc(p,0) returns non-null, such as
> 	the BSDs or musl libc, it is simpler to handle it:
> 
> 		new = realloc(old, size);
> 		if (new == NULL) {  // errno is ENOMEM
> 			free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	Whenever the result is a null pointer, these platforms are
> 	reporting an ENOMEM error, and thus it is superfluous to check
> 	errno there.
> 
> 	Most code is written in this way, even if run on platforms
> 	returning a null pointer.  This is because most programmers are
> 	just unaware of this problem.  Part of the reason is also that
> 	returning a non-null pointer with zero bytes is the natural
> 	extension of the behavior, which is what programmers intuitively
> 	expect from libc; that is, if realloc(p,3) allocates 3 bytes,
> 	r(p,2) allocates two bytes, and r(p,1) allocates one byte, it is
> 	natural by induction to expect that r(p,0) will allocate zero
> 	bytes.  Most algorithms naturally extend to 0 just fine, and
> 	special casing 0 is artificial.
> 
> 	If the realloc(3) specification were changed to require that
> 	realloc(p,0) returns non-null on success, and that realloc(p,0)
> 	only fails when out-of-memory (and assuming the implementations
> 	will continue setting errno to ENOMEM), then code written for
> 	AIX or glibc would continue working just fine, since the errno
> 	check would be redundant with the null check.  Simply, the
> 	conditional (errno == ENOMEM) would always be true when
> 	(new == NULL).
> 
> 	Then, there are non-POSIX platforms that don't set ENOMEM.  In
> 	those platforms, code might do this:
> 
> 		new = realloc(old, size);
> 		if (new == NULL) {
> 			if (size != 0)
> 				free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	That code would continue working with this proposal, except for
> 	a very rare corner case, in which it would leak.  In the normal
> 	case, (size != 0) would never be true under (new == NULL),
> 	because a reallocation of 0 bytes would almost always succeed,
> 	and thus not return a null pointer under this proposal.
> 	However, in some cases, the system might not find space even for
> 	the small metadata needed for a 0-byte allocation.  In such
> 	case, the (size != 0) conditional would prevent deallocating
> 	'old', and thus cause a memory leak.  This case is exceptional
> 	enough that it shouldn't stop us from fixing realloc(3).
> 	Anyway, on an out-of-memory case, the program is likely to
> 	terminate rather soon, so the issue is even less likely to have
> 	an impact on any existing programs.  Also, LLVM's address
> 	sanitizer will soon able to catch such a leak:
> 	<https://github.com/llvm/llvm-project/issues/113065>
> 
> 	This proposal makes handling of realloc(3) as straightforward as
> 	one would expect, with only two states: success or error.  There
> 	are no in-between states.
> 
> 	The resulting wording in the standard is also much simpler, as
> 	it doesn't need to define so many special cases.
> 
> 	For consistency, all the other allocation functions are updated
> 	to both return a null pointer on error, and use consistent
> 	wording.
> 
>     Why not go the other way around?
> 	Some people keep asking why not go the other way around: why not
> 	force the BSDs and musl to return a null pointer if size is 0.
> 	This would result in double-free and use-after-free bugs, which
> 	can result in RCE vulnerabilities (remote code execution), which
> 	is clearly unacceptable.
> 
> 	Consider this code, which is the usual code for calling
> 	realloc(3) in such systems:
> 
> 		new = realloc(old, size);
> 		if (new == NULL) {
> 			free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	If realloc(p,0) would return a null pointer and free the old
> 	block, then the third line would be a double-free bug.
> 
> Prior art
>     gnulib
> 	gnulib provides the realloc-posix module, which aims to wrap the
> 	system realloc(3) and reallocarray(3) functions so that they
> 	behave in a POSIX-complying manner.
> 
> 	It previously behaved like glibc.  After I reported that it was
> 	non-conforming to POSIX, we discussed the best way forward,
> 	which we agreed was the same direction that this paper is
> 	proposing now for C2y.  The implementation was changed in
> 
> 		gnulib.git d884e6fc4a60 (2024-11-04; "realloc-posix: realloc (..., 0) now returns nonnull")
> 
> 	There have been no regression reports since then, as we
> 	expected.
> 
>     V7 Unix, BSD
> 	The proposed behavior is the one endorsed by Doug McIlroy, the
> 	author of the original implementation of realloc(3) in V7 Unix,
> 	and also present in the BSDs.
> 
>     glibc <= 2.1
> 	glibc was implemented originally to return non-null.  It was
> 	only in 1999, and purely to comply with the standards --with no
> 	requests by users to do so--, that the glibc maintainers decided
> 	to switch to the current behavior.
> 
> Design decisions
> 	This change needs two changes, which can be applied all at once,
> 	or in separate steps.
> 
> 	The first step would make realloc(p,s) be consistent with
> 	free(p) and malloc(s), including when p is a null pointer, when
> 	s is zero, and also when both corner cases happen at the same
> 	time.  This change would already turn the implementations where
> 	malloc(0) returns non-null into the end goal we have.  This
> 	would require changes to (at least) the following
> 	implementations: glibc, Bionic, Windows.
> 
> 	The second step would be to require that malloc(0) returns a
> 	non-null pointer.  This would require changes to (at least) the
> 	following implementations: AIX.
> 
> 	This proposal has merged all steps into a single proposal.
> 
> Future directions
> 	This proposal, by specifying realloc(3) as-if by calling
> 	free(3) and malloc(3), makes redundant several mentions of
> 	realloc(3) next to either free(3) or malloc(3) in the standard.
> 	We could remove them in this proposal, or clean up that in a
> 	separate (mostly editorial) proposal.  Let's keep it for a
> 	future proposal for now.
> 
> Caveats
>     n?n:1
> 	Code written today should be careful, in case it can run on
> 	older systems that are not fixed to comply with this stricter
> 	specification.  Thus, code written today should call realloc(3)
> 	similar to this:
> 
> 		realloc(p, n?n:1);
> 
> 	When all existing implementations are fixed to comply with this
> 	stricter specification, that workaround can be removed.
> 
>     ENOMEM
> 	Existing implementations that set errno to ENOMEM must continue
> 	doing so when the input pointer is not freed.  If they didn't,
> 	code that is currently portable to all POSIX systems
> 
> 		errno = 0;
> 		new = realloc(old, size);
> 		if (new == NULL) {
> 			if (errno == ENOMEM)
> 				free(old);
> 			goto fail;
> 		}
> 		...
> 		free(new);
> 
> 	would leak on error.
> 
> 	Since it is currently impossible to write code today that is
> 	portable to arbitrary C17 systems, this is not an issue in
> 	ISO C.
> 
> 		-  New code written for C2y will only need to check for
> 		   NULL to detect errors.
> 
> 		-  Code written for specific C17 and older platforms
> 		   that don't set errno will continue to work for those
> 		   specific platforms.
> 
> 		-  Code written for POSIX.1-2024 and older platforms
> 		   will continue working on POSIX C2y platforms,
> 		   assuming that POSIX will continue mandating ENOMEM.
> 
> 		-  Code written for POSIX.1-2024 and older will not be
> 		   able to be run on non-POSIX C2y platforms, but that
> 		   could be expected.
> 
> 	The only important thing is that platforms that did set ENOMEM
> 	should continue setting it, to avoid introducing leaks.
> 
> Proposed wording
> 	Based on N3550.
> 
>     7.25.4.1  Memory management functions :: General
> 	@@ p1
> 	...
> 	-If the size of the space requested is zero,
> 	+If the total size of the space requested is zero,
> 	-the behavior is implementation-defined:
> 	-either
> 	-a null pointer is returned to indicate the 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.
> 
>     7.25.4.2  The aligned_alloc function
> 	@@ Returns, p3
> 	 The <b>aligned_alloc</b> function returns
> 	-either
> 	-a null pointer
> 	-or
> 	-a pointer to the allocated space.
> 	+a pointer to the allocated space
> 	+on success.
> 	+If
> 	+the space cannot be allocated,
> 	+a null pointer is returned.
> 
>     7.25.4.3  The calloc function
> 	@@ Returns, p3
> 	 The <b>calloc</b> function returns
> 	-either
> 	 a pointer to the allocated space
> 	+on success.
> 	-or a null pointer
> 	-if
> 	+If
> 	 the space cannot be allocated
> 	 or if the product <tt>nmemb * size</tt>
> 	-would wraparound <b>size_t</b>.
> 	+would wraparound <b>size_t</b>,
> 	+a null pointer is returned.
> 
>     7.25.4.7  The malloc function
> 	@@ Returns, p3
> 	 The <b>malloc</b> function returns
> 	-either
> 	-a null pointer
> 	-or
> 	-a pointer to the allocated space.
> 	+a pointer to the allocated space
> 	+on success.
> 	+If
> 	+the space cannot be allocated,
> 	+a null pointer is returned.
> 
>     7.25.4.8  The realloc function
> 	@@ Description, p2
> 	 The <b>realloc</b> function
> 	 deallocates the old object pointed to by <tt>ptr</tt>
> 	+as if by a call to <b>free</b>,
> 	 and returns a pointer to a new object
> 	-that has the size specified by <tt>size</tt>.
> 	+that has the size specified by <tt>size</tt>
> 	+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.
> 
> 	@@ 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
> 	+or return a different pointer
> 	+for a call that shrinks the block of memory.
> 
> 	@@ Returns, p4
> 	 The <b>realloc</b> function returns
> 	 a pointer to the new object
> 	 (which can have the same value
> 	-as a pointer to the old object),
> 	+as a pointer to the old object)
> 	+on success.
> 	-or
> 	+If
> 	+space cannot be allocated,
> 	 a null pointer
> 	-if the new object has not been allocated.
> 	+is returned.
> 
> -- 
> <https://www.alejandro-colomar.es/>



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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                           ` <87ms9jlcgw.fsf@gmail.com>
@ 2025-07-05  0:43                             ` Alejandro Colomar
  0 siblings, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-07-05  0:43 UTC (permalink / raw)
  To: Collin Funk
  Cc: Eric Blake, Rich Felker, enh, Florian Weimer,
	Adhemerval Zanella Netto, musl, libc-alpha, Joseph Myers,
	наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 1794 bytes --]

Hi Collin,

On Fri, Jul 04, 2025 at 05:15:27PM -0700, Collin Funk wrote:
> Alejandro Colomar <alx@kernel.org> writes:
> 
> > BTW, I was trying to find out the history of memccpy(3), and why it was
> > introduced in 4.4BSD.  Does anyone know the history?  I find it a weird
> > function that doesn't have any good use case, or I don't seem to see it.
> > Every use case I see, such as a poor-man's strlcpy(3), seems to be prone
> > to off-by-one errors, or have other APIs that would be more ergonomic.
> > What were the original uses in 4.4BSD?
> 
> In the sources for 2.11 BSD you can find the following in
> include/strings.h:
> 
>     /* Routines described in memory(BA_LIB); System V compatibility */
>     char	*memccpy(), *memchr(), *memcpy(), *memset(), *strchr(),
>     	*strdup(), *strpbrk(), *strrchr(), *strsep(), *strtok();
> 
> The first time I can see the function defined is in Eigth Edition Unix.

Hmmm, so the FreeBSD manual page seems incorrect:

$ find -type f | grep memccpy.3 | MANWIDTH=72 xargs man 2>/dev/null | sed -n '/HISTORY/,$p'
HISTORY
       The  memccpy()  function  first appeared in 4.4BSD and was first
       specified in the .  The restrict keyword was added to the proto‐
       type in FreeBSD 5.0.0 in accordance with the updated  specifica‐
       tion of IEEE Std 1003.1-2004 (“POSIX.1”).

Debian                      December 5, 2023                 MEMCCPY(3)

Okay, I'll look into V8 Unix.  At least now I know where to search.
Thanks!  :)

> You can look for yourself here, <https://www.tuhs.org/cgi-bin/utree.pl>.
> 

Yup, thanks!  I was thinking it would be in 4.4BSD, according to
FreeBSD.  Unix should be easier to search.


Have a lovely day!
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0)
       [not found]                         ` <ymigejkdbyrxohd5chrigpfvztnia2nw4u3jmdiw6vke2xs3me@xb5t6hevzuba>
       [not found]                           ` <87ms9jlcgw.fsf@gmail.com>
@ 2025-07-05  2:28                           ` Alejandro Colomar
  1 sibling, 0 replies; 38+ messages in thread
From: Alejandro Colomar @ 2025-07-05  2:28 UTC (permalink / raw)
  To: Eric Blake
  Cc: Rich Felker, enh, Florian Weimer, Adhemerval Zanella Netto, musl,
	libc-alpha, Joseph Myers, наб,
	Paul Eggert, Robert Seacord, Bruno Haible, bug-gnulib,
	JeanHeyd Meneide, Thorsten Glaser

[-- Attachment #1: Type: text/plain, Size: 1415 bytes --]

Hi Eric,

On Sat, Jul 05, 2025 at 01:31:38AM +0200, Alejandro Colomar wrote:
> > > > 		-  POSIX.1-2001
> > > 
> > > This one defers to C89 anywhere that it is not explicitly documenting
> > > with CX shading.
> > 
> > Ahh, I had thought it would defer to C99 because it's older, but I guess
> > it's like POSIX.1-2024 that doesn't defer to C23.  Thanks!  Then I stand
> > corrected, and glibc conforms to POSIX.1-2001.
> 
> I was reading the memccpy(3) specification in POSIX.1-2004, and found
> this:
> 
> 	Issue 6
> 
> 		The restrict keyword is added to the memccpy() prototype
> 		for alignment with the ISO/IEC 9899:1999 standard.
> 
> So, Issue 6 aligned with ISO C99?  Is this exceptional, or does then
> POSIX.1-2001 not defer to ISO C89?


POSIX.1-2004 certainly seems to be using deferring to C99, as it has the
c99(1) shell utility.

<https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap02.html#tag_02_01_04_02>

and has several references to ISO/IEC 9899:1999.

<https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap02.html#tag_02_02_01>

But I didn't find any to C89.

Which means, glibc didn't conform to POSIX.1-2004 (and much likely,
neither to POSIX.1-2001; but I don't have a link to that).  Anyway, I
guess n3612 will solve our problems forever, hopefully.  See you!  :)


Cheers,
Alex

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2025-07-05  2:29 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <qukfe5yxycbl5v7ooskvqdnm3au3orohbx4babfltegi47iyly@or6dgf7akeqv>
2025-06-16 16:40 ` [musl] Re: BUG: realloc(p,0) should be consistent with malloc(0) enh
2025-06-16 21:21   ` Alejandro Colomar
2025-06-16 18:20 ` Adhemerval Zanella Netto
     [not found]   ` <87y0trv5sq.fsf@oldenburg.str.redhat.com>
2025-06-16 20:59     ` Adhemerval Zanella Netto
2025-06-16 21:44     ` Alejandro Colomar
     [not found]       ` <CAJgzZooXcPUVJ7Z3Nae-2WRsjpFnNVZpGU0aJyysM2Mv89PSgg@mail.gmail.com>
     [not found]         ` <20250617145104.GX1827@brightrain.aerifal.cx>
     [not found]           ` <CAJgzZoqfDpmig=oCJyrZC9=w1DLnDOeqMk_A5LgJ689_6pZr2g@mail.gmail.com>
     [not found]             ` <20250617165644.GY1827@brightrain.aerifal.cx>
2025-06-17 17:38               ` Re[2]: " Laurent Bercot
2025-06-17 21:58             ` Alejandro Colomar
     [not found]               ` <mvmmsa56opb.fsf@suse.de>
2025-06-18 18:05                 ` Alejandro Colomar
     [not found]               ` <CAJgzZopU2xDpuYkbJ-W9rURTCFL0tQEYrXKYu7rmkG+UVZzVKw@mail.gmail.com>
     [not found]                 ` <20250618163550.GZ1827@brightrain.aerifal.cx>
2025-06-18 19:04                   ` Alejandro Colomar
     [not found]                     ` <4b5wiz62y5pq5hiepuqwjt7gmfbu2lnz5nalxrocl2yzxowdx7@m6sus2kdvepw>
     [not found]                       ` <1804ec5c-d024-448e-beb2-f682384c70d4@cs.ucla.edu>
2025-06-20 10:04                         ` Vincent Lefevre
     [not found]                       ` <2sqn2ggwgtgjhrd7p57ipbxqe7ncpk3c5rmyvvqlumvyecsk5q@ufffzvlrnvpk>
2025-06-20  2:11                         ` Vincent Lefevre
     [not found]                           ` <l47kg74zm6wukxn7hm3lot73bt5huhtal32fhpj25aozfncuw7@qgf5o3m5do5o>
2025-06-20 14:36                             ` Vincent Lefevre
2025-06-20 14:56                               ` Alejandro Colomar
2025-06-20 13:42                         ` Mark Harris
2025-06-20 16:18                           ` Joseph Myers
2025-06-21  3:57                         ` Sam James
     [not found]                         ` <ymigejkdbyrxohd5chrigpfvztnia2nw4u3jmdiw6vke2xs3me@xb5t6hevzuba>
     [not found]                           ` <87ms9jlcgw.fsf@gmail.com>
2025-07-05  0:43                             ` Alejandro Colomar
2025-07-05  2:28                           ` Alejandro Colomar
2025-06-20 21:26 ` [musl] alx-0029r1 - Restore the traditional realloc(3) specification Alejandro Colomar
2025-06-20 22:31   ` [musl] " Christopher Bazley
2025-06-21  1:59     ` Alejandro Colomar
2025-06-20 22:58   ` Maciej W. Rozycki
     [not found]     ` <xdt4l76ircncs6kh5ikhdsn5hsmh3wwceecl2pzg6zmqr7i2sm@slquforl5gfu>
2025-06-21 14:49       ` Markus Wichmann
2025-06-21 16:27         ` Rich Felker
     [not found]   ` <c5c35b74-bc56-e0f1-3608-05aac48f1be3@mirbsd.de>
     [not found]     ` <sqztyjgk6yopge2y3skaxhlcfvaslmrh7rhuxwrlkc5iyf3tec@rcadeufr43uk>
     [not found]       ` <1aaa9a0f-8425-4c48-8698-65a3765a67a2@cs.ucla.edu>
     [not found]         ` <euw6h6yxp6mghwcajrfvp7fzvafazyafl4jtbjf334kg6kfkfu@x5tkgo6kfomt>
2025-06-21  3:50           ` Paul Eggert
     [not found]   ` <limjtao3jpge6hrrjliko4w6p5t7cfpbc3m3etodqgsxayi3hw@gv4eml5icqb5>
     [not found]     ` <p55v5kpblnzvg4eatx2hmlrsbjkybtd4syy7zbjiza6wv4xv2u@o25g6qru3ppx>
2025-06-24  9:07       ` [musl] Re: alx-0029r3 " Florian Weimer
2025-06-24  9:54         ` Bruno Haible
2025-06-24 14:18         ` Alejandro Colomar
     [not found]           ` <CAH8yC8n4Xf1uvcNCvycvrn4SvjWN2ttXFW6-75tyEbtUO916MQ@mail.gmail.com>
     [not found]             ` <20250625001927.GP1827@brightrain.aerifal.cx>
2025-06-25 14:10               ` enh
     [not found]       ` <lqwifu3d5rcevgbzskyxgqlxceznlougry6tbtote5xbt37u7s@kynjo4ncdocj>
2025-06-24 23:01         ` Alejandro Colomar
2025-06-25  1:58   ` [musl] alx-0029r4 " Alejandro Colomar
     [not found]     ` <u4vvv6oflabxrzaxqt5axeuiit4zpyyidmzn7zxz2sswjcuaqs@5xiezwem7mds>
     [not found]       ` <nfgzup5c6x5figox5tf6uvfym5cswmmysppyzx5cfngjwkycjf@lyv4t6wmuu6t>
     [not found]         ` <2fetsqzfiztwbhkybwuvysvjt2oa64n6vkgjbgeuhti3eahwjh@wunpix75de4t>
     [not found]           ` <yc3bptzhluejuxaawnjgwu234ii7dwmxsacmaa6tyrx2tslkc4@bw2dnt3rlgbl>
2025-06-25 18:07             ` [musl] " Wilco Dijkstra
2025-06-25 18:20               ` Eric Blake
2025-06-25 18:21               ` Alejandro Colomar
     [not found]   ` <ttmksxnr4ojqqkereep5j5vkakz5wg5e24mjvbllj6u5ibvn5k@e7jslgr5dt2b>
     [not found]     ` <CAMdZqKGoCO6xmzq1=+Oa_xe4emeKRxY6FEaN3cY6mW6mUb6ggw@mail.gmail.com>
2025-06-27  1:51       ` [musl] Re: alx-0029r5 " Alejandro Colomar
2025-06-27  8:52     ` Florian Weimer
2025-06-27 13:26       ` Alejandro Colomar
     [not found]   ` <vl4fdi3ohhclxsgjhzz27owlxl7dh3gnjslykaiphwta6f66cc@alqxmrejng53>
2025-06-30  2:27     ` [musl] Re: alx-0029r6 " Alejandro Colomar

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).