Note that, in compiler lingo, unspecified and undefined are two different things. C++ is specified to death, but full of undefined behavior (and also some unspecified behavior).
Rust is largely not specified, but aims to have no undefined behavior (outside of unsafe blocks).
I am aware but without a spec we don’t know which is which. You can’t say it has no undefined behavior because what happens is you try to specify it and find gaps or challenges.
In C undefined is used primarily when there is not a reliable and efficient mechanism for detecting a problem is happening. For example a C implementation may check every single invalid pointer deref, but more realistically it only detects only extreme out of range. So it’s undefined what happens.
> I am aware but without a spec we don’t know which is which.
I don't think I fully agree with this. A more accurate statement might be that "without a spec we don't always know which is which". You obviously don't need a spec to pin down at least some of a language's behavior, and even then the presence of a spec doesn't necessarily mean that you can answer arbitrary questions about what behavior is intended (c.f., various defect reports in the C/C++ spec asking clarifying questions, pointing out holes/deficiencies, or even admitting that certain behavior is not intended but being unsure about how to forbid it)
Good point.
That being said, at least in C++, undefined has been used largely as a joker for compiler optimizations. In Rust, if my memory serves, having the same code produce different results depending on the optimization level would be considered a pretty serious bug. In C++, it's par for the course.