> C23 furthermore gives the compiler license to use an unreachable annotation on one code path to justify removing, without notice or warning, an entirely different code path that is not marked unreachable: see the discussion of puts() in Example 1 on page 316 of N3054.9<p>I don't agree with that description at all. Here's the code:<p><pre><code> 1 if (argc <= 2)
2 unreachable();
3 else
4 return printf("%s: we see %s", argv[0], argv[1]);
5 return puts("this should never be reached");
</code></pre>
The only code path that's "entirely different" is lines 1,4,5 and in that case of course you remove a return that's after a return.<p>And the other valid code path is 1,2,5, which has `puts` after `unreachable`.<p>To need `puts` you have to imagine a code path that gets past the "if" without taking either branch?<p>Maybe the author means something by "code path" that's very different from how I interpret it?<p>I would be pretty surprised if the above code means something different from:<p><pre><code> if (argc <= 2) {
unreachable();
return puts("this should never be reached");
} else {
return printf("%s: we see %s", argv[0], argv[1]);
return puts("this should never be reached");
}</code></pre>
This is written with quite a lot of hyperbole.<p>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: <a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf" rel="nofollow">https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf</a>. Note that this wasn’t a proposal to change something, it’s a defect report: the original wording was never suitable.<p>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.<p>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.<p>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.
I actually like unreachable() a lot. What it does is that it invokes undefined behavior, that's all.<p>It does nothing trickier than any other kind of UB. In fact, I could implement unreachable() like this: void unreachable() { (char *)0 = 1; }.<p>Standardizing it however gives interesting options for compilers and tool writers. The best use I can find is to bound the values of the argument of a function. For example, if we have "void foo(int a) { if (a <= 0) unreachable(); }, it tells the compiler that a will always be >0 and it will optimize accordingly, but it can also be used in debug builds to trigger a crash, and static analyzers can use that to issue warnings if, for example, we call foo(0). The advantage of using unreachable() instead of any other UB is that the intention is clear.
> and that such changes may impose themselves on old code without recompilation when dynamically linked libraries are upgraded.<p>All I can do is laugh. This is what the dynamic linker fanatics wanted. This is what they explicitly advocate for to this day. Share and enjoy!!
> C178 purports to be a bug-fix revision of C11. Does the word "toto" on page 1 indicate (a) the editor's musical tastes; (b) that nobody bothered to spell-check the document; (c) that we're not in Kansas anymore; or (d) none of the above?<p>As a french guy I'd go with (d).<p>I've often seen "toto" used as a placeholder name, sometimes followed by "titi", "tata", "tutu", I have even used it myself. It is similar to "foo", "bar", "baz". I don't know if it is specific to France, of French speaking countries, but it is definitely a thing here.
Frankly, the C standards ctte went off the deep end when they effectively banned NULL to memset etc (obv with zero length).<p>Not because these functions couldn't handle it, but because this assertion simplifies optimizations <i>elsewhere</i>.<p>This has required adding extra checks in my code, found mainly by trial and error, and has made it less readable <i>and</i> less optimal.<p>Finally, the checked arithmetic operations returning <i>false</i> 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 :(
Author is angry but not wrong. Lifting the most damning quote from the article as I haven't seen it for a while.<p>C inventor Dennis Ritchie pointed to several flaws in [ANSI C] ... which he said is a licence for the compiler to undertake agressive opimisations that are completely legal by the committee's rules, but make hash of apparently safe programs; the confused attempt to improve optimisation ... spoils the language.<p>—Dennis Ritchie on the first C standard
> The ckd_* macros steer a refreshingly sane path around arithmetic pitfalls including C's "usual arithmetic conversions."<p>A 7 letter function to add two numbers and that returns a boolean... not entirely sure I'd call that 'sane'.
Is the world finally realizing that "a + b" actually returns two values: pass/fail and the value if pass?<p>"a + b = c;" is a fundamentally flawed operation from a computer architecture perspective.
"Looking forward, marijuana legalization will surely beget notions such as fractional-, imaginary-, and negative-length objects, each with as much potential for mayhem as zero-length objects."<p>It's a funny thing to say.
Maybe I'm being dense. To me it appears that the standards are telling compiler writers what should be done. In doing so the compilers will become ever more complex and thus bug-prone.<p>I learnt C back when K&R (first edition) was the reference. Ok, it was hardly much more than a universal assembler to make every computer look like a PDP-11. In my experience C is the language to use when you want to be close to the metal. For the rest I use which ever high-level language/environment is best suited. Admittedly some FFI are a pain to use, but once you get the boilerplate bedded down your much higher level language gets the coordination done.
C reached its zenith in C90, and saw a few good ideas in C99. Everything since has been wankery from people who either are bored, or have a severe case of C++-envy.
> All C standards from C89 onward have permitted compilers to delete code paths containing undefined operations—which compilers merrily do, much to the surprise and outrage of coders.16 C23 introduces a new mechanism for astonishing elision: By marking a code path with the new unreachable annotation,12 the programmer assures the compiler that control will never reach it and thereby explicitly invites the compiler to elide the marked path.<p>I don't agree with this in the slightest. I'm not "outraged" by undefined behaviour, it's a <i>fundamental tool</i> for writing performant code. Ensuring that dereferencing a null pointer or accessing outside the bounds of an array is undefined behaviour is what lets the compiler not emit a branch on every array access and pointer dereference.<p>Furthermore, I really don't understand the outrage that there is another <i>explicit</i> tool to achieve behaviour the author may or may not consider harmful. If it's an explicit macro, it's not a tarpit!
While the situation with realloc() is unfortunate, it is also not difficult to write a wrapper that does what the author wants. I’ve done that before, because it has long been known that not all realloc() implementations conform to the (prior) C standard. One can furthermore assume that existing implementations won’t change their behavior just because C23 made it UB.
Is it just me that thinks that the article is a [skilfully drafted] joke (or parody or whatever the correct word is)? The fact that it has been published close to April 1st raises more suspicions.
I always wonder how much these new C standards use, as C is now mostly used in areas where one is severely limited when it comes to compiler choice. Where I work, we use GCC 6.2 and iso9899:1990 (C90). If we were able to use a modern compiler, we would probably just use C++.
> Pointers to free'd memory are akin to uninitialized pointers, so free(p) followed by if (p==q) is an instrument of arson<p>What's the reason for this?
tl;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)<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<p>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<p>Lest we have to stop using realloc outside of a safe_realloc wrapper<p><pre><code> static void *safe_realloc(void *p, size_t newlen)
{
if (newlen == 0) { free(p); return NULL; }
return realloc(p, newlen);
}
</code></pre>
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-zero
#embed is what I really want. And separators.<p>> Standard C advances slowly<p>They're not joking, either. C is conservative to a fault, I think.
And zero focus on improving the root causes of memory corruption due to strings and array indexing errors.<p>The security world will keep burning it seems.
> As C89 was taking shape, the neurodivergent notion of a "zero-length object" was making the rounds<p>I'm surprised that the authors decided to, and were able to, slip in this little euphemism.