Live data from Hacker News

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

community.intel.com

51–60 of 76 posts

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

#51

I love how in C++ there seems to be this security issue, and now hundreds of people try to come up with different ways on how to tackle the problem. Everybody wants to help and spend their free time on it. You don't see this in other languages so much. People just use those languages and "they" have to fix any flaws. Also keep your bingo cards ready for people saying Rust does not have undefined behaviour. I'm also n…

> You don't see this in other languages so much. People just use those languages and "they" have to fix any flaws.

You absolutely do see that elsewhere, and that's why here on HN we have a different new JS framework every day.

The safety in Rust (and .NET, and Java) doesn't come from the `unsafe` keyword, it comes from the guarantees that you have when you don't use said keyword. Ownership, garbage collectors, and less undefined behaviour are some reasons why those languages are considered safer.

At the end, memory safety is a spectrum, and while you can still break Rust's (or even Java's) memory model, it's much harder to do so unintentionally. That's a win. Even if there are some undefined edge cases!

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

#52

I love how in C++ there seems to be this security issue, and now hundreds of people try to come up with different ways on how to tackle the problem. Everybody wants to help and spend their free time on it. You don't see this in other languages so much. People just use those languages and "they" have to fix any flaws. Also keep your bingo cards ready for people saying Rust does not have undefined behaviour. I'm also n…

Do tou have data to back up these claims?

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

#53
post #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.

The spec explicitly does not define the boundaries of all UB. Look at the note on the definition in 1.3.24 and the context of the surrounding definitions:

    Undefined behavior may be expected when this International Standard omits any explicit definition of behavior...
Rather than having specific causes, UB is simply the label given to "stuff outside the standard with no requirements whatsoever". Some of this stuff is important and much more of it isn't. A small subset of that infinite universe of UB is the set of enumerated undefined behaviors you're talking about, where the standard declines to specify any requirements in certain situations. These are what the annex is trying to organize.

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

#54
post #41

Earlier quoted context omitted.

And C has a UB study group and we are working on a technical rapport that in great detail describes how UB works in C, and a comprehensive list of sample code for all known UB.

Is there hope that we could some day achieve an exhaustive lists of all undefined behavior that C programmers need to be aware of? I realize no one really knows today, but is there a path?

Thw C standard has a list of all known UBs. We don't know if the list is complete, because the C standard makes anything not defined by omission UB, so its possible to discover new UB. The language is however pretty thoroughly explored.

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

#55

Earlier quoted context omitted.

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.

> they aren't messy, they're fully defined. Integer overflow in safe Rust works just like Java: the numbers wrap around. That is both fully defined and messy. They are not mutually exclusive. It means there are integers where n+1 is less than n. That is messy. No integers that I learned about in math class work like that. The only two non-messy well-defined behaviours are 1) bignums by default like in Python, but not…

> No integers that I learned about in math class work like that.

Did you learn about modular arithmetic in math class?

> The only two non-messy well-defined behaviours are 1) bignums by default like in Python, but not suitable for a low level language like Rust; or, 2) trap on overflow, like Ada is supposed to do though it is usually shut off by a pragma. Both of those have significant runtime cost.

No, they're not the only "non-messy" behaviors. An example of where wraparound is the desired behavior is computing hash functions. An example of where saturating arithmetic is the desired behavior is processing audio samples.

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

#56

Earlier quoted context omitted.

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…

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…

The key is that you can't get rid of it entirely, which is why Rust has `unsafe.`

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

#58
post #30

Earlier quoted context omitted.

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.

Panics can be aborts if set in cargo.toml.

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

#59
post #47
post #35

Earlier quoted context omitted.

How does Rust implement this on targets where LLVM does not implement stack clash protection?

On Unix targets it installs a signal handler for SIGSEGV and checks if the faulting address falls within the range of the stack guards. See https://github.com/rust-lang/rust/blob/411f34b/library/std/s... The stack guards would normally be setup by the system runtime (e.g. kernel in the case of the main thread stack, libc for thread stacks), not Rust's runtime. Likewise, stack probes that ensure stack operations don't…

The runtime thing is the easy part. I was wondering about the stack probes, which require LLVM support. There's a comment in the sources that suggest it's still x86-only, but that may be outdated:

“ //! Finally it's worth noting that at the time of this writing LLVM only has //! support for stack probes on x86 and x86_64. There's no support for stack //! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would //! be more than welcome to accept such a change! ”

https://github.com/rust-lang/compiler-builtins/blob/master/s...

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

#60
post #33

Earlier quoted context omitted.

And even better, start reducing the list after it's complete, by pushing things like integer overflow into implementation defined; several uses of inc/decrement operators into compilation error; and etc.

I don't want integer overflow to be implementation defined though, I want it undefined so my compiler can optimize my code for the fact that I don't overflow my integers in the first place.

The implementation can define the behavior on overflow to be the optimized behavior. Optimization and UB are orthogonal concepts.
Post reply on HN