Live data from Hacker News

Why do we need for an Undefined Behavior Annex to C++

community.intel.com

21–30 of 76 posts

Re: Why do we need for an Undefined Behavior Annex to C++

#21

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?

What they are listing is not the undefined behaviors, but rather the C++ language constructs which might lead to them.

Re: Why do we need for an Undefined Behavior Annex to C++

#22

Earlier 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…

things are still a bit messy with integer overflow

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++

#23
post #3

Great 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.

The hard part of UB isn't where it's mentioned in the standard. The problem is when the standard says "in case A, X occurs, in case B, Y occurs" then somebody invents a situation where neither A nor B apply.

Re: Why do we need for an Undefined Behavior Annex to C++

#24

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?

There's already a bunch of stuff in the standard which explicitly says, "if you do xyz, the behavior is undefined". Stuff doesn't become "defined" just because the standard points out that it's not defined.

Re: Why do we need for an Undefined Behavior Annex to C++

#25
post #18
post #17

Earlier 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.

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 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++

#27

Earlier 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…

> There's lots of things beyond bounds checks that constitute UB and bounds checks are but 1 small item.

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++

#28

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?

It’s a poor name all around, because the spec already precisely defines boundaries of what is UB — “if this and this happens, the behavior is undefined”.

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++

#29
post #18

Earlier 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…

[deleted]

Re: Why do we need for an Undefined Behavior Annex to C++

#30
post #18

Earlier 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…

Panics are not quite the same as an abort in Rust. Most notably a panic can be caught and execution can resume so as to gracefully terminate the application, but an abort is an immediate termination, a go to jail do not pass go kind of situation.

An out of bounds access in Rust will result in a panic but a stack overflow is an abort.

Post reply on HN