49 points ibobev 20 hours ago 84 comments
MiroslavPokorny 15 hours ago | parent
One can browse other blog entries so it really doesnt matter too much.
Aurornis 1 hour ago | parent
saghm 9 minutes ago | parent
BobbyTables2 1 hour ago | parent
Idiots!
Don’t they really that people write real programs to solve real problems? This isn’t a theoretical academic exercise!
bryanlarsen 1 hour ago | parent
vlovich123 1 hour ago | parent
bryanlarsen 1 hour ago | parent
IIUC, my understanding is shallow.
nicoburns 1 hour ago | parent
vlovich123 45 minutes ago | parent
Sharlin 1 hour ago | parent
kibwen 1 hour ago | parent
nh2 1 hour ago | parent
It breaks the most fundamental debugging expectations (such as "delete code until problem disappears") if the fundamental, minimal building blocks of a language, when on their own, do random rubbish.
To understand a program that does something, better first understand a program that does nothing.
As a fan of sensible analogies:
You put a salad bowl with vinegar into the fridge and notice that when you do that, the fridge stinks afterwards. You try again without the vinegar, then without the salad. In C++ world, upon receiving the empty bowl, the fridge detonates ("it is not useful"), blowing up your house. That is not OK.
Jaxan 1 hour ago | parent
vlovich123 43 minutes ago | parent
rcxdude 14 minutes ago | parent
lou1306 1 hour ago | parent
bluGill 1 hour ago | parent
If it wasn't so hard to detect (the trivial cases are easy, but it gets hard quickly) I'd say the program should fail to compile.
echoangle 1 hour ago | parent
bluGill 1 hour ago | parent
echoangle 59 minutes ago | parent
bluGill 3 minutes ago | parent
Now that I think of it, a different project (I worked just down the aisle, but I wasn't on it) solved a lot customer complaints by turning all the "while(1);" loops into blink an error code - which since it does IO is defined behavior. Which probably is the correct answer to your question - don't just spin doing nothing, spin in such a way that the user has a clue why nothing is broken (and in turn you can find out and perhaps fix real world bugs)
adzm 1 hour ago | parent
kzrdude 1 hour ago | parent
Someone 1 hour ago | parent
raverbashing 1 hour ago | parent
If I think about asm:
function1:
(do stuff)
jp function1
ret
function2: (other stuff)
ret
main: call function1
call function2
the 2nd call might happen internally due to branch prediction but in practice it shouldn't and the processor fixes thisOh yeah and TFA also goes with:
> The funny bit is that C got this right.(...) but C included one more rule: loops whose controlling expression is a constant expression may not be assumed to terminate.
Well, duh! A broken clock is right twice a day it seems
rcxdude 1 hour ago | parent
echoangle 1 hour ago | parent
rcxdude 1 hour ago | parent
lou1306 1 hour ago | parent
This is literally the opposite behaviour compared to what is written in the source code, even when you "assume the infinite loop terminates".
echoangle 1 hour ago | parent
rcxdude 1 hour ago | parent
rcxdude 1 hour ago | parent
Probably the process was one optimization pass saw that the function will never return due to an infinite loop, and removed the function return from the IR of the function, then a later pass saw that the infinite loop was a no-op and undefined so removed that as well, leaving a function that basically did nothing, not even return.
echoangle 30 minutes ago | parent
Not really true, most instructions set have instructions specifically to implement functions as found in normal programming languages. x86 has CALL and RET for example.
https://en.wikipedia.org/wiki/X86_calling_conventions
Of course the compiler can stil optimize by inlining etc., but functions still mostly exist at the assembly level.
rcxdude 19 minutes ago | parent
apple1417 1 hour ago | parent
main:
unreachable():
push rbx
...
Due to the undefined behavior, it decides calling main must be impossible, so the easiest thing to do is just give up, don't bother defining the rest of it. You can also do the same with std::unreachable(). But the label for the function still sticks around for some reason, so when you jump to it, it falls through. Which leads to the really stupid fact that reordering the functions changes the behavior.I assume there are good reasons they can't just completely delete the label. Maybe it would screw linking, or with cases where you deliberately have multiple labels for the same function. And if the effect is only visible due to undefined behavior, it's not technically wrong. But I have always thought this is such a stupid case, surely it can't be that complex to add a trap instruction, even in an optimized build you shouldn't really care if it slows down a function that's "never called".
rcxdude 1 hour ago | parent
oleganza 1 hour ago | parent
Guvante 1 hour ago | parent
Null being an "allowed" value for pointers is the mistake e.g. what became nullptr. "Allowed" because garbage values are garbage.
account42 1 hour ago | parent
DonaldPShimoda 1 hour ago | parent
Anyway, one argument is that UB is fundamentally useful in languages that are insufficiently type-safe, like C and C++. The "holes" in the specification allow for regions where the compiler can optimize the code in ways you may not expect.
As we have developed more advanced type systems, the utility of undefined behavior has lessened considerably.
returningfory2 1 hour ago | parent
> As far as I can tell, C89 did not use performance as a justification for any of its undefined behaviors. They were non-portabilities, like signed overflow and null pointer dereferences, or they were outright bugs, like use-after-free. But now experts like Chris Lattner and Hans Boehm point to optimization potential, not portability, as justification for undefined behaviors. I conclude that the rationales really have shifted from the mid-1980s to today: an idea that meant to capture non-portability has been preserved for performance, trumping concerns like correctness and debuggability.
nicoburns 1 hour ago | parent
ameliaquining 59 minutes ago | parent
account42 1 hour ago | parent
echoangle 1 hour ago | parent
> What I found is that this is common in embedded and kernel code as a halt-on-error pattern. When a fatal error occurs and there’s no operating system to exit to, you simply stop:
account42 1 hour ago | parent
mdspan 1 hour ago | parent
rcxdude 1 hour ago | parent
echoangle 1 hour ago | parent
account42 56 minutes ago | parent
echoangle 29 minutes ago | parent
pdonis 54 minutes ago | parent
weinzierl 1 hour ago | parent
sumtechguy 1 hour ago | parent
That seems to be a very broad statement. For example in a system where interrupts mostly control things this sort of 'do not close the program' could be useful.
A guy I worked with had one I never would think of because I do not work in that field.
But yeah a warning would probably be useful.
not_the_fda 1 hour ago | parent
mdspan 1 hour ago | parent
aabolfazl 1 hour ago | parent
JoshTriplett 1 hour ago | parent
Insert screaming here.
An infinite loop, with no library calls whatsoever, gets a system call inserted. That's a horrible surprise waiting to happen.
The entire concept of the "forward progress guarantee" is broken. An infinite loop should compile to an infinite loop. Nothing more, nothing less.
rcxdude 1 hour ago | parent
ameliaquining 58 minutes ago | parent
rcxdude 56 minutes ago | parent
JoshTriplett 44 minutes ago | parent
rfgplk 12 minutes ago | parent
This then forces developers to create undefined behaviour because according to the standard you can't namespace std your own functions even though it's required to get it to work.
ozgrakkurt 40 minutes ago | parent
Also performance doesn't matter that much and developer time is more important btw, keep using react.
muvlon 4 minutes ago | parent
ibobev 21 minutes ago | parent
I think that a compiler option should control this. It can be a nice optimization, but the programmer should be able to opt out.
saghm 11 minutes ago | parent
ameliaquining 1 hour ago | parent
omoikane 1 hour ago | parent
https://www.sandordargo.com/blog/2026/09/16/cpp26-trivial-in...
Edit: sorry, missed the UB bit.
omoikane 1 hour ago | parent
This seems to say that the loop body can not be "continue". Indeed, I just tried -std=c++26 with ";" and got an infinite loop as promised, but "continue" restores the undefined behavior:
- "while(true);" -> https://godbolt.org/z/T65o51crx
- "while(true) continue;" -> https://godbolt.org/z/Pj9raEcnP
This is unfortunate since I know of one style guide that prefers "continue" over single semicolons. I guess all those code will be doing "while(true) {}" from now on.
https://google.github.io/styleguide/cppguide.html#Formatting...
wahern 1 hour ago | parent
That's the epitome of the hidden code downside that Linus and many others dislike about C++. For constructors and destructors it's somewhat unavoidable and not so random, though Rust does better at limiting the blast radius of non-local code, at least in the drop case.
If they didn't want to adopt the C11 rule, the C++ committee should've explored a rule that required the compiler to emit a diagnostic or error for trivial loops (whether as defined by C11 or otherwise), requiring the programmer to explicitly insert ::yield or similar. No hidden code, and less opportunity for the compiler to do surprising things.
The C committee has been rigorously enumerating UB cases in the standard and addressing each case in turn, often by requiring a diagnostic, error, or by turning it into implemention defined behavior. But inserting code like that would be unthinkable.
IsTom 55 minutes ago | parent
It wouldn't work when this kind of loop is generated by macros/templates in some unreachable case left after const folding.
rcxdude 46 minutes ago | parent
IsTom 39 minutes ago | parent
rfgplk 5 minutes ago | parent
<meta> is the single WORST OFFENDER, where they hardcode std::vector (literally std::vector in the std namespace) std::ranges std::allocator.
peterus 1 hour ago | parent
I only use it for error handling and of course it is a bad idea to use this to wait/stall in power sensitive applications, in that case use wake from interrupt.
As an aside, I like to include a software breakpoint in my error handlers. It makes debugging easier without wasting a hardware breakpoint (which are physically limited by the microcontroller):
__BKPT();
while (1)
;shmerl 1 hour ago | parent
rcxdude 49 minutes ago | parent
In a lot of cases, you might insert some 'wait-for-interrupt' type instruction in the loop that halts the CPU more 'cleanly' (and in a lower power mode), and usually this will appear as a side-effect and keep the behaviour defined. But this is not always desirable or possible.