I know, the goal is (in short) a listing of expected undefined behavior, which could improve security if developers follow along. But isn't putting undefined behavior into the standard an oxymoron, kinda?
Why do we need for an Undefined Behavior Annex to C++
21–30 of 76 posts
Re: Why do we need for an Undefined Behavior Annex to C++
#22Earlier quoted context omitted.
No, because UB is not avoidable in principle unless you create a walled garden/sandbox that must be enforced at non-zero runtime cost.
I don’t know. Safe rust has 0 UB although if I recall correctly things are still a bit messy with integer overflow. I could imagine a world where we define annotations around “signed integer will never overflow” that you can add to hit paths but otherwise disallow optimizing around that UB and for all other UB require an explicit annotation acknowledging it or just a warning and a missed optimization instead. The cur…
No, they aren't messy, they're fully defined. Integer overflow in safe Rust works just like Java: the numbers wrap around. It's totally defined.
You can, optionally, also enable a runtime check for this wraparound. This is usually enabled for debug builds. There is of course a performance cost to doing this.
Re: Why do we need for an Undefined Behavior Annex to C++
#23Great stuff. It looks like a ton of upfront work, but will greatly improve the standard, and shouldn't be too hard to maintain once it's complete.
Once it's complete, make it authoritative. Any mention of undefined behavior should be required to reference the corresponding item in the UB annex.
Re: Why do we need for an Undefined Behavior Annex to C++
#24I know, the goal is (in short) a listing of expected undefined behavior, which could improve security if developers follow along. But isn't putting undefined behavior into the standard an oxymoron, kinda?
Re: Why do we need for an Undefined Behavior Annex to C++
#25Earlier quoted context omitted.
> Safe rust has 0 UB Safe Rust aims for 0 UB, but I don't think you can make the claim that it absolutely has no UB. This program SEGFAULTs on my system (macOS), because it's reading an invalid memory address due to a stack overflow: const N: usize = 1024*1024*1024; fn main() { let var: [u8; N] = [0; N]; println!("var: {:?}", var); }
Safe Rust has no undefined behavior. Undefined behavior does not mean no crashing, it means that the semantics of the program are undefined. Rust's semantics are to abort on a stack overflow. A language like C or C++ have no such semantics, they may abort or they may continue running and producing jibberish.
EDIT: Going to take it back. I'm unable to create a situation where I create a large stack array that doesn't result in an immediate stack overflow. I even tried nightly MaybeUninit::uninit_array but that crashed explicitly with a "fatal runtime error: stack overflow" so it seems like the standard library has improved reporting instead of the old SEGFAULT. So no UB.
Re: Why do we need for an Undefined Behavior Annex to C++
#26Re: Why do we need for an Undefined Behavior Annex to C++
#27Earlier quoted context omitted.
The key is "that must be enforced at non-zero runtime cost." Safe Rust is indeed generally free of UB, but that requires bounds checks at a minimum. > I could imagine a world where we define annotations around “signed integer will never overflow” that you can add to hit paths but otherwise disallow optimizing around that UB That's kind of what Rust does - overflow is not UB, but you can use unchecked_add/mul/div/sub…
There's lots of things beyond bounds checks that constitute UB and bounds checks are but 1 small item. Generally Rust avoids the runtime cost of that through a three prong strategy of idiomatic Rust amortizing the cost of a bounds check to 0 (e.g. efficient iterator implementations that don't need bounds checks), eliding the check altogether if the compiler can prove it's duplicate / unneeded for some reason, or prov…
Indeed, hence "at a minimum". The type system and choosing to avoid UB when defining some operations helps a lot as well, but those have no direct overhead so there's no runtime cost there. Bounds checks (and overflow checks, if those are ever added to release mode) are just the one thing that have a direct runtime cost when they aren't elided.
Re: Why do we need for an Undefined Behavior Annex to C++
#28I know, the goal is (in short) a listing of expected undefined behavior, which could improve security if developers follow along. But isn't putting undefined behavior into the standard an oxymoron, kinda?
These are precisely defined situations, that in modern compilers’ interpretation, are forbidden from ever happening in any program under any circumstances.
UB is only a name for nebulous consequences of violating these very specific prohibitions.
Re: Why do we need for an Undefined Behavior Annex to C++
#29Earlier quoted context omitted.
Safe Rust has no undefined behavior. Undefined behavior does not mean no crashing, it means that the semantics of the program are undefined. Rust's semantics are to abort on a stack overflow. A language like C or C++ have no such semantics, they may abort or they may continue running and producing jibberish.
I don't know if it's technically UB or well defined. The crash is a SEGFAULT and not a panic/abort, but it's probably a SEGFAULT due to guard pages. Still, it's possible to evade guard pages so if you access var[X] such that X points to the heap, it's possible you're reading aliased memory which would be UB in safe Rust. EDIT: Going to take it back. I'm unable to create a situation where I create a large stack array…
Re: Why do we need for an Undefined Behavior Annex to C++
#30Earlier quoted context omitted.
Safe Rust has no undefined behavior. Undefined behavior does not mean no crashing, it means that the semantics of the program are undefined. Rust's semantics are to abort on a stack overflow. A language like C or C++ have no such semantics, they may abort or they may continue running and producing jibberish.
I don't know if it's technically UB or well defined. The crash is a SEGFAULT and not a panic/abort, but it's probably a SEGFAULT due to guard pages. Still, it's possible to evade guard pages so if you access var[X] such that X points to the heap, it's possible you're reading aliased memory which would be UB in safe Rust. EDIT: Going to take it back. I'm unable to create a situation where I create a large stack array…
An out of bounds access in Rust will result in a panic but a stack overflow is an abort.