|
|
Subscribe / Log in / New account

C17 definition of realloc(_, 0)

C17 definition of realloc(_, 0)

Posted Jul 24, 2024 20:48 UTC (Wed) by khim (subscriber, #9252)
In reply to: C17 definition of realloc(_, 0) by farnz
Parent article: GNU C Library 2.40 released

> Keeping it like it was in C17 is making it undefined behaviour, just with obfuscated language to hide that from people who don't spend all their time following through the implications of standardese.

Tell me what gives compiler writer the right to turn this function:

int foo(int x) {
  int y = x * 2;
  realloc(malloc(1), 0);
  return y;
}

into empty sequence of instructions (without even ret at the end). We may go from there.

> If the C17 definition was OK, then simplifying the language used to define it but keeping the definition the same should also be OK.

Only if you explain how the optimization described above is allowed. I coudn't see how C17 may allow that. C23, most definitely, makes it Ok.

> It would have been better to redraft the C17 language so that you couldn't select the set of options that make it UB, but that's not what the committee chose to do - in large part (as far as I can tell as a non-attendee) because any attempt to change the allowed set of options upset people who felt that other people were Wrong to implement realloc(_, 0) the way they did.

And, instead, they have picked an approach which would make every single one of these people ask about sanity of people who pushed this approach to the language. Is it really an improvement?

> Rather than continue trying to find some way to make it work for two groups who refuse to agree, the wording just got simplified to remove the long chain of logic leading to it being UB, since the two conflicting groups can just as easily define it downstream if they care.

Except we already know where that leads: no one would bother to do anything, but compiler writers, few years down the road, would interpret the wording in the most ruinous way possible.

That decisions would be funny if not for the past experience with this exact function.


to post comments

realloc(malloc(1), 0) as UB under C17 rules

Posted Jul 24, 2024 22:40 UTC (Wed) by farnz (subscriber, #17727) [Link] (4 responses)

It's a nasty little mistake in drafting, in paragraph 3 of 7.22.3.5, and clearly a defect. However, the standard only imposes requirements on realloc if memory for the new object is not allocated. It is permissible for realloc to allocate a new object, but not to allocate memory for that new object (since it's zero sized); at this point, the general escape hatch in 3.4.3 is open, since the standard imposes no requirements here, and you've got UB on a technicality. It then returns a non-null pointer, since it allocated an object, and you're in the bad place since the standard doesn't say what to do with the old object.

Now, this is clearly a drafting error and should be fixed by removing "memory" - but, AFAICT, people got angry at the idea of fixing the drafting error without also fixing the required behaviour to match their idea of the "only correct" way to define this. And rather than deal with that, the standards committee chose to simply open the escape hatch wide and say "screw you all".

I personally think this was the wrong decision, but it's the decision the committee made. And it's reflective of the current direction of travel of C - rather than make hard decisions for the benefit of users of the language (since the smaller the area covered by undefined behaviour, the easier it is to work within the language), they've chosen to punt a hard problem at the users and rely on "real programmers not making mistakes". I doubt history will be kind to the C committee over this, since it's clearly a case of "it's easier for us to do this, even if it makes life harder for language users".

realloc(malloc(1), 0) as UB under C17 rules

Posted Jul 25, 2024 8:42 UTC (Thu) by khim (subscriber, #9252) [Link] (3 responses)

> It is permissible for realloc to allocate a new object, but not to allocate memory for that new object (since it's zero sized)

Objects is a “region of data storage in the execution environment”, if you don't have a storage then you can't have an object.

It's unclear whether zero-sized objects are even possible in C17 (it makes it impossible to have zero-sized arrays or structs, but doesn't say if zero-sized objects are possible to get from realloc), but I don't see how the definition of object as “regions of data storage in the execution environment” permits you to allocate one without also allocating memory (maybe zero bytes of memory!) for it. Sorry. No “region of data storage in the execution environment”, no object. It's as simple as that.

The worst you can expect from C17 AFAICS is that realloc would allocate one, single, zero-sized region of storage for objects and would hand over different pointers to that same single region with all-identical bits.

That's a bit of strange situation, sure, but it's still not UB. In Rust that's perfectly normal, defined (and often used!) behavior, I don't see how and why C should be different.

realloc(malloc(1), 0) as UB under C17 rules

Posted Jul 25, 2024 15:11 UTC (Thu) by farnz (subscriber, #17727) [Link] (2 responses)

C is different because the standard says that unless it explicitly defines something, that thing is UB. And in this case, by talking about memory in this one clause (something which, unlike a region of storage, is undefined), it infects the whole clause with UB if you're sufficiently motivated to find UB in a program.

If they'd not thrust that word "memory" in, this would be a full definition; but by adding an undefined term, the licence to treat the whole clause as UB is introduced.

realloc(malloc(1), 0) as UB under C17 rules

Posted Jul 25, 2024 15:37 UTC (Thu) by khim (subscriber, #9252) [Link] (1 responses)

> C is different because the standard says that unless it explicitly defines something, that thing is UB.

Yes, but that doesn't include terms. For unknown terms it defers to ISO/IEC 2382.

> And in this case, by talking about memory in this one clause (something which, unlike a region of storage, is undefined)

Are you sure it's not defined? I suspect it's common enough term than ISO/IEC 2382, somehow.

> it infects the whole clause with UB if you're sufficiently motivated to find UB in a program.

No, unknown terms like that. They may be interpreted differently, because not all combinations of ISO standard terms have meaning, but that would be a defect in the standard, it wouldn't, suddenly, lead to UB.

For something to be UB it shouldn't be defined at all, not defined in a strange and/or undeciperable manner.

Otherwise you may pick some term which is not defined by C standard but used extensively enough (e.g. syntax is mentioned many times, but never defined) and then claim that standard doesn't define anything at all.

realloc(malloc(1), 0) as UB under C17 rules

Posted Jul 25, 2024 15:45 UTC (Thu) by farnz (subscriber, #17727) [Link]

All I can tell you is that this is the argument given by acquaintances on the committee - syntax is defined by ISO 2382, but memory is not, which is why there's wiggle-room for saying that the behaviour is undefined.

I, personally, think this is sucky, because you shouldn't be stretching to find UB whenever possible, but should be trying to reduce it to the minimum reasonable scope, but that's not current C culture.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds