Catch-23: The New C Standard Sets the World on Fire
queue.acm.org
Catch-23: The New C Standard Sets the World on Fire
1–10 of 275 posts
Re: Catch-23: The New C Standard Sets the World on Fire
#2Seems a bit tone deaf to create new undefined behavior in memory handling, especially when a sane default behavior seems to be de facto
I've used that free-on-0 behavior myself. Unfortunately the code that uses this will often have 0 be a length variable, so hard to grep for this. Ideally musl/glibc will both stick to that undefined behavior being free & gcc/clang won't go about making this something to point their optimizations at
Lest we have to stop using realloc outside of a safe_realloc wrapper
static void *safe_realloc(void *p, size_t newlen)
{
if (newlen == 0) { free(p); return NULL; }
return realloc(p, newlen);
}
What got this whole thing weird is that C doesn't like zero sized objects, but implementations were allowed to return a unique pointer for a zero sized allocation. Which then raises the matter that being portable there require freeing that reserved chunk for non-free implementations. In theory this reservation code could be more efficient when code frequently reallocates between 0 & some small value. & there was uncertainty because NULL is a way to say allocation failure, but then if one did a NULL check on realloc's return value they also had to check that the size was non-zeroRe: Catch-23: The New C Standard Sets the World on Fire
#3The predominant focus is realloc(pre,0) becoming UB instead of what the author misleadingly describes as useful, consistent behaviour. It is far from that, and that’s the entire reason that it was declared UB in the first place: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf. Note that this wasn’t a proposal to change something, it’s a defect report: the original wording was never suitable.
The second part is the misconception about the impact of UB. Making something UB does not dictate that its usage will initiate the rise of zombie velociraptors. It grants the implementation the power to decide the best course of action. That is, after all, what they’ve been doing all this time anyway.
Note that this deviates from implementation-defined behaviour, because an implementation-defined behaviour has to be consistent. Where implementations choose to let realloc(ptr,0) summon the zombie raptors, they are free to do so. Don’t like it? Don’t target their implementation. Again, this isn’t a change from the POV of implementers - it’s a defect in the existing wording.
In this case, the course of action that any implementation will choose is to stick with the status quo. It is clearly not a deciding factor in whether or not you embrace the new standard, and to suggest otherwise is dishonest, sensationalist nonsense. The feature was broken, and it’s just being named as such.
Re: Catch-23: The New C Standard Sets the World on Fire
#4"a + b = c;" is a fundamentally flawed operation from a computer architecture perspective.
Re: Catch-23: The New C Standard Sets the World on Fire
#5This is written with quite a lot of hyperbole. The predominant focus is realloc(pre,0) becoming UB instead of what the author misleadingly describes as useful, consistent behaviour. It is far from that, and that’s the entire reason that it was declared UB in the first place: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf . Note that this wasn’t a proposal to change something, it’s a defect report: the ori…
That being said, you're completely wrong about what UB means. Making use of UB may as well initiate the rise of zombie velociraptors. Except for the situation where your implementation explicitly specifies that it provides a predictable behaviour for a specific case of UB, there's literally no guarantee of what will happen. Assuming that the implementation will stick with some status quo and your code won't exhibit absolutely unusual behaviour is just naiive.
Please don't mislead people into thinking that it's ever a good idea to assume that undefined behaviour will be handled sensibly, this kind of mislead assumption is one of the major sources of bugs in C code.
Re: Catch-23: The New C Standard Sets the World on Fire
#6tl;dr `realloc(p, 0)` is slated to be undefined behavior in C23, whereas it's been somewhat implementation defined until now, with recommendation being realloc(p, 0) is equivalent to free(p) Seems a bit tone deaf to create new undefined behavior in memory handling, especially when a sane default behavior seems to be de facto I've used that free-on-0 behavior myself. Unfortunately the code that uses this will often ha…
It's only tone deaf to people who understand "undefined behavior" as an epithet or as synonymous with giving a license to compilers to screw you over. The term doesn't have either of those meaning to those on the C committee. In fact, one of the explicit rationales for the proposal is that, "Classifying a call to realloc with a size of 0 as undefined behavior would allow POSIX to define the otherwise undefined behavior however they please." https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf
> especially when a sane default behavior seems to be de facto
The above proposal, N2464, gives the behavior for AIX, zOS, BSD (unspecified), MSVC (crt unspecified), and glibc. They each have different behaviors.
Why they chose to finally make it undefined (it was marked as obsolescent for a long time) rather than keep it as implementation-defined, I don't know. Perhaps because it 1) simplifies the standard, and 2) by making it undefined it suggests compilers should start warning about it--despite all this time neither has there arisen a consensus among implementations about the best behavior, nor are programmers aware that the behavior actually varies widely.
EDIT: The draft SUSv5/POSIX-202x standard has indeed directly addressed this issue. See, e.g., https://www.austingroupbugs.net/view.php?id=374 The most recent draft included the following addition to RETURN VALUE:
OB If size is 0,
OB CX or either nelem or elsize is 0,
OB either:
OB * A null pointer shall be returned
OB CX and, if ptr is not a null pointer, errno shall be set to [EINVAL].
OB * A pointer to the allocated space shall be returned, and the memory object pointed to by ptr
shall be freed. The application shall ensure that the pointer is not used to access an object.
CX marks points of divergence with C17. The first CX is because of the addition of reallocarray, absent from C17. The second is because POSIX will mandate the setting of EINVAL if NULL is returned.Re: Catch-23: The New C Standard Sets the World on Fire
#7This is written with quite a lot of hyperbole. The predominant focus is realloc(pre,0) becoming UB instead of what the author misleadingly describes as useful, consistent behaviour. It is far from that, and that’s the entire reason that it was declared UB in the first place: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf . Note that this wasn’t a proposal to change something, it’s a defect report: the ori…
Wrong, Wrong, Wrong.
UB allows the implementation to take any arbitrary course of action, without informing anyone, without documentation, without any conscious decision, without weighing anything to be better/worse. Nondeterministically catching fire and launching nuclear rockets is a completely compliant reaction to UB.
What you are describing is "implementation defined" behavior. That has to be deterministic, documented, and conforming to some definition of sanity. Examples are the binary representation of NULL, sizes of integer types or stuff like the maximum filename length. Sadly, too many things in C have "undefined behavior", too few have "implementation defined" behavior.
And UB has always been an excuse for compilers to screw over programmers in hideous ways. Programmers are rightfully afraid of any kind of new UB being introduced, because it will mean that whole new classes of bugs will arise because the compiler optimized out that realloc(..., a) where a might be 0, because thats UB, so screw you and your code... And this change is especially dangerous because it makes a lot of existing code UB.
Re: Catch-23: The New C Standard Sets the World on Fire
#8Is the world finally realizing that "a + b" actually returns two values: pass/fail and the value if pass? "a + b = c;" is a fundamentally flawed operation from a computer architecture perspective.
A more sophisticated type system.
Let's say you had some pseudocode like this:
let a = 5
let b = 12
let c = a + b
The type of a would be Integer[5..5], the type of b would be Integer[12..12], the type of c would therefore be Integer[17..17]. In a more complex example: def foo(a: Integer[0..10], b: Integer[0..10]):
return a + b
The return type of this function would be Integer[0..20].This kind of type system can solve a number of issues, all but division by zero (which would probably still have to be solved with some kind of optional type).
If type inference dictates that the upper range of an integer would be too large to physically store in a machine data type, then you either resort to bignums or you make it a compilation error. By adding modular and saturating integer types you can handle situations where you want special integer behaviours. By explicitly casting (with the operation returning an optional) you can handle situations where you want to bound the range. This drastically simplifies a lot of code by removing explicit bounds checks in all places except where they are absolutely necessary. If for some reason you care about the space or computational efficiency of the underlying machine type, you can have additional annotations (like C's u?int_(least|fast)[0-9]+_t). If you absolutely must map to a machine type (this is usually misguided, unless you are dealing with existing C interfaces, for which such a language can provide special types) you can have more annotations.
Ada has something resembling this. I believe there are some other languages that implement similar features. I believe this sort of thing has a name, but I am not great with remembering the names of things.
Hopefully this is some food for thought.
Re: Catch-23: The New C Standard Sets the World on Fire
#9Not because these functions couldn't handle it, but because this assertion simplifies optimizations elsewhere.
This has required adding extra checks in my code, found mainly by trial and error, and has made it less readable and less optimal.
Finally, the checked arithmetic operations returning false on success is a horror show. Fortunately it will be found on the first time the code is run, but that's a damnably low bar :(
Re: Catch-23: The New C Standard Sets the World on Fire
#10It's a funny thing to say.