Why is null-terminated C string considered a "billion dollar mistake", but UB isn't?
Null terminated strings were an intentional compromise, known to be inferior for execution but superior for memory
Null being an "allowed" value for pointers is the mistake e.g. what became nullptr. "Allowed" because garbage values are garbage.
This comes from a fundamental misunderstanding of what UB is.
Think of this piece of code - `y * x / y`.
Would you like to simplify it to just `x` ?
You need to either lean on UB to do so or have some magical way to prove that y can not be 0.
Otherwise this transformation changes behavior, and is illegal.
Probably because null-terminated strings are completely avoidable, whereas some amount of UB is all but required for performance (albeit C and C++ have far too much).
I recommend this explanation of why UB is good and necessary (but C and C++ are doing it wrong, defining some things as UB that really shouldn't be): https://www.ralfj.de/blog/2021/11/18/ub-good-idea.html
The "billion-dollar mistake" was about implicitly nullable values, i.e., allowing a variable with type `T` to also be set to `null`, not null-terminated strings.
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.