If people prefer "performance trumps correctness" and "winning compiler benchmarks is what counts" then they should happily keep getting exploited.
for many cases it is in fact equivalent to the halting problem. What you can do is check at runtime, which has performance implications (from trivial to expensive depending on the check).
This is what the alternatives in the memory safe systems programming language since Algol days do.
Surely they still allow for developers to disable some of those checks explicitly, but then it is the programmers fault to choose "performance trumps correctness" instead of "correctness trumps performance".
The halting problem is impossible to solve for arbitrarily evil programs, but that doesn't mean that it's impossible to write programs that are easy to analyse.
There are middle grounds, of course: you can let the compiler figure out on its own what it can, and let it insert runtime checks for the other cases.
And add some way for the programmer to declare that eg "warn me if this can't be optimized" or "trust me, this is safe" or even "here's a proof for you".
But in any case, dependent types are possible---undecidability is not a hard barrier here.
Possible? Yes. Too time-consuming and fiddly for the economic realities of 99.9% of all programmers? Yes, that too.
At least that how bank regulation works out in practice.
However I don't see it ever happening in the UNIX world, only on OSes whose architecture is not bound to the traditional UNIX/C culture.
Which is why see as positive that Apple, Google and Microsoft are pushing C and C++ down into the very lowest layers of their OS stacks, mostly visible on Google's case.
Even straight pure Assembly programming has less UB surprises.
And yes, if you want to allow manual allocation of objects and setting pointers to arbitrary objects, then your two choices are: 1) garbage collection 2) undefined behavior (use-after-free, double-free, dangling pointers, etc.)
Garbage collection isn't the only way of writing mostly safe systems programs.
ESPOL, NEWP are 10 year older than C.
PL/8 was the systems programming language used by IBM for their first RISC mainframe, followed by PL/S.
Mesa used at Xerox PARC.
Modula-2 used at ETHZ and many 16 bit systems.
Object Pascal used to write the first versions of Mac OS and Lisa.
Ada and SPARK used by high integrity systems where human lives can be at risk.
All of them with not even a quarter of C's UB collection.
- ADA requires garbage collection
- Modula-2 and Object pascal have manual memory management, i.e.: "new" and "delete" - together with double-free, use-after-free, and dangling pointers...
I agree that C is by far worse, but please recognize that at least some of the undefined behavior problems are really hard to solve.
EDIT: Oh, and we haven't started talking about multi threading yet, have we?
"writing mostly safe systems programs."
Do you understand what mostly means?
Ada and Modula-2 have multi-threading as part of their ISO/ANSI language standard.
Also you don't seem to know much about Ada given your GC remark, but here is some learning.
https://archive.fosdem.org/2016/schedule/event/ada_memory/
Of course there are still use cases where Algol derived languages are still unsafe, however those use cases are a tiny portion of what happens in C land.
That's uncalled for, man...
> Of course there are still use cases where Algol derived languages are still unsafe, however those use cases are a tiny portion of what happens in C land.
On that I agree - there are many problems we wouldn't have if we were using, say, pascal or modula.
> Also you don't seem to know much about Ada given your GC remark, but here is some learning.
I'm sorry, I don't have time to watch that. However, I know that ADA has either GC or manual memory management (with the deallocation method explicitly marked as unsafe). Thus, as far as i know, constructing "use-after-free" in Ada is possible - which is undefined behavior (and that was my point).
For example, leaking data in Rust is a perfectly safe thing to do. But while destructors help to prevent it, they cannot guarantee that nothing ever leaks. (And some of this depends on what you mean by "leaking" and so on.)
use-after-free, double-free and dangling pointers are all handled by Rust's ownership and borrowing systems.