Live data from Hacker News

Undefined Behavior in 2017

blog.regehr.org

51–60 of 120 posts

Re: Undefined Behavior in 2017

#51
post #22

The main message from my point of view: > Be knowledgeable about what’s actually in the C and C++ standards since these are what compiler writers are going by. Avoid repeating tired maxims like “C is a portable assembly language” and “trust the programmer.” > Unfortunately, C and C++ are mostly taught the old way, as if programming in them isn’t like walking in a minefield. Nor have the books about C and C++ caught u…

I think it's the compilers that have perverted the language to such an extent that it's become ridiculously difficult to understand, and so it's the compilers that must change back to being less obtuse and adversarial.

The C standard even suggests, when defining undefined behaviour, that one of the possible options is "behaving during translation or program execution in a documented manner characteristic of the environment". If signed int arithmetic on the hardware wraps around upon overflow, then take that into account when optimising and don't assume it can't overflow. This is how C programmers want the language to work; compiler writers and standards be damned.

I've written plenty of Asm and also looked at as much if not more compiler output; and while the latter sometimes pleasingly surprises me, it's usually pretty evident that it was not generated by an intelligent entity. (And countless times, I've obtained size and/or speed savings by replacing the latter with what I would otherwise write.) My general impression is that there aren't enough highly-skilled Asm programmers working on compiler development --- there are many reasons I can think of for that, but one of the things I've always wished to exist is a simple, straightforward C compiler with "understandable" output and optimisation that creates results closer to what a human Asm programmer might write; with the associated optimisation advantages and predictability. This means not assuming anything just because the standard says so, but taking a more holistic (for lack of a better word) approach to compilation and optimisation.

A long-time favourite post on this: http://blog.metaobject.com/2014/04/cc-osmartass.html

Re: Undefined Behavior in 2017

#52
post #45

Earlier quoted context omitted.

>If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. Sure and I believe that adding a conditional qualification such as "if one does not invoke UB of LLVM" restates my point: one can't make a universal statement that "safe Rust has zero undefined behavior." E.g., as of this writing, the following "safe Rust" UB issue (3+ years ago) last had comments 21 days ago and…

>a conditional qualification such as "if one does not invoke UB of LLVM" A conditional qualification which is intended to be unconditionally true of safe Rust code, outside bugs in the compiler. The universal statement is totally possible, because your conditional is equivalent to saying "if you write valid code".

>which is _intended_ to be unconditionally true of safe Rust code,

I emphasized "intended" because it seems like we're talking past each other.

You: re-emphasizing Rust's specified design goal.

Me: emphasizing the current state of Rust compiler as reality which makes the statement "safe Rust has no undefined behavior" as not true.

(In other words, I emphasize the unintentional UB whereas you do not.)

>, because your conditional is equivalent to saying "if you write valid code".

If you look at the github issue, "1.04E+17 as u8" is valid safe Rust code which invokes UB.

Re: Undefined Behavior in 2017

#53
post #45
post #42

Earlier quoted context omitted.

If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. I don't know enough to guarantee or verify it, but it's my current understanding that this is the case.

>If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. Sure and I believe that adding a conditional qualification such as "if one does not invoke UB of LLVM" restates my point: one can't make a universal statement that "safe Rust has zero undefined behavior." E.g., as of this writing, the following "safe Rust" UB issue (3+ years ago) last had comments 21 days ago and…

If somebody asks you what "cat" does, do you say "It copies its input to its output, unless there's a bug in cat or the C compiler that compiled it or cosmic rays hit the program on disk"?

Re: Undefined Behavior in 2017

#54
post #45
post #42

Earlier quoted context omitted.

If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. I don't know enough to guarantee or verify it, but it's my current understanding that this is the case.

>If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. Sure and I believe that adding a conditional qualification such as "if one does not invoke UB of LLVM" restates my point: one can't make a universal statement that "safe Rust has zero undefined behavior." E.g., as of this writing, the following "safe Rust" UB issue (3+ years ago) last had comments 21 days ago and…

[deleted]

Re: Undefined Behavior in 2017

#55
post #22

The main message from my point of view: > Be knowledgeable about what’s actually in the C and C++ standards since these are what compiler writers are going by. Avoid repeating tired maxims like “C is a portable assembly language” and “trust the programmer.” > Unfortunately, C and C++ are mostly taught the old way, as if programming in them isn’t like walking in a minefield. Nor have the books about C and C++ caught u…

I think it's the compilers that have perverted the language to such an extent that it's become ridiculously difficult to understand, and so it's the compilers that must change back to being less obtuse and adversarial. The C standard even suggests, when defining undefined behaviour, that one of the possible options is "behaving during translation or program execution in a documented manner characteristic of the envir…

> If signed int arithmetic on the hardware wraps around upon overflow, then take that into account when optimising and don't assume it can't overflow. This is how C programmers want the language to work;

Don't speak for all of us.

Some of us may take the language for what it is, instead of assuming it to be a "high level portable assembler" which it is not, but which a particular implementation of it may be, thanks to the standard leaving much up to the implementation.

It is this same leeway that (thankfully) allows smart optimizing compilers that can generate performant code for programs that are not omgwtf-optimized at the source level.

And it is this same leeway that allows very simplistic, naive implementations that do not go out of their way to perform crazy analysis to try and warn you about some corner case of undesirable behavior your code might hit.

You're right that it is the compilers can and need to change to accommodate different types of users. But I don't think every compiler should just go back to being a 1991 compiler; not every compiler needs to accommodate every user.

Re: Undefined Behavior in 2017

#56
post #46

> Loops that Neither Perform I/O nor Terminate > Summary: This UB is probably not a problem in practice (even if it is moderately displeasing to some of us). Since LLVM is mostly based around C/C++ semantics this actually turned out to be a problem for rust, because rust can encode diverging functions in its type system and assume certain code sections to be unreachable. If the compiler then optimizes out code and th…

I think that's a great example of how optimisers have gone off the deep end: no reasonable human programmer would think "I can't figure out if this loop terminates, so let's just leave it out", but that appears to be the default behaviour in this case --- when what should happen when the optimiser "gives up" is that it should just translate the code verbatim.

Re: Undefined Behavior in 2017

#57
post #40

Earlier quoted context omitted.

> Note that all of these are inside of unsafe blocks. Besides unsafe blocks, Rust has no undefined behavior, and the compiler will prevent you from doing any of these things. It's true that unsafe is needed to get these problems, but they can also occur outside of unsafe blocks. See an example here: https://gankro.github.io/blah/only-in-rust/#unbound-lifetime... Your own code need not use "unsafe" at all, but the pro…

The important quote from the article you linked is: "But what happens when we throw some unsafe code at the issue?", so the claim that safe Rust doesn't have UB (that isn't considered a bug in the compiler) still stands. If you mix in unsafe code, bad things may happen, regardless of whether you wrote the unsafe yourself or rely on a library.

> the claim that safe Rust doesn't have UB (that isn't considered a bug in the compiler) still stands

Yes!

> If you mix in unsafe code, bad things may happen

Yes!

My point was only that those bad things may also happen after the unsafe block that is their root cause. This is in reply to parent's "all of these [UBs] are inside of unsafe blocks". They aren't. They are caused by something inside unsafe blocks, but they may also materialize after.

Re: Undefined Behavior in 2017

#58
post #45

Earlier quoted context omitted.

>If safe Rust code does not invoke any of the UB corners of LLVM then Rust can claim to be free from UB. Sure and I believe that adding a conditional qualification such as "if one does not invoke UB of LLVM" restates my point: one can't make a universal statement that "safe Rust has zero undefined behavior." E.g., as of this writing, the following "safe Rust" UB issue (3+ years ago) last had comments 21 days ago and…

If somebody asks you what "cat" does, do you say "It copies its input to its output, unless there's a bug in cat or the C compiler that compiled it or cosmic rays hit the program on disk"?

>If somebody asks you what "cat" does,

Yes I get what you're saying but I'll try to emphasize again that I'm not trying to play semantic games to irritate everyone. (Yes, we can play word games such as "a tank is an armored military vehicle -- unless it is just a cardboard facade to fool Germans that the Allies are invading a different a part of France's coastline or acting as a movie prop for special effects work.") Every "thing" can be defined with endless cumbersome qualifiers that nobody actually says in real life.

That said, I felt the context in this thread warranted a different threshold to qualify Rust's UB because one example of John Regehr 200 UB bullet points is:

  - Demotion of one real floating type to another produces a value outside the range that can be represented (6.3.1.5).
The Rust UB github issue is not exactly the same cast but similar in spirit. Therefore, justinpombrio's comment that "Besides unsafe blocks, Rust has no undefined behavior," doesn't look accurate to me in the context of this UB thread rather than just casual speech about Rust. I can't read the mind of the poster asking the question (chrisdew) to know exactly what his scope of "UB" included but I think the reality of unintentional UB in Rust is relevant in this particular conversation.

Re: Undefined Behavior in 2017

#59
post #25
post #2

How many of these 200+ undefined behaviours exist in more modern low-level languages, such as Rust and D?

LuaJIT is another modern low-level language. It has some remarkable undefined behavior like the evaluation order for function arguments. Scares me a bit. https://github.com/LuaJIT/LuaJIT/issues/238

This would not be what is called undefined behavior per the C standard, but unspecified or implementation-defined behavior. The bad thing about "undefined behavior" is that the implementation is basically allowed to do whatever it wants, while unspecified and implementation-defined behavior still has sane semantics. Unspecified behavior allows the language implementation to choose any one from several possible implementations, implementation-defined behavior requires the language implementation to define the semantics itself.

Re: Undefined Behavior in 2017

#60
post #46

> Loops that Neither Perform I/O nor Terminate > Summary: This UB is probably not a problem in practice (even if it is moderately displeasing to some of us). Since LLVM is mostly based around C/C++ semantics this actually turned out to be a problem for rust, because rust can encode diverging functions in its type system and assume certain code sections to be unreachable. If the compiler then optimizes out code and th…

I think that's a great example of how optimisers have gone off the deep end: no reasonable human programmer would think "I can't figure out if this loop terminates, so let's just leave it out", but that appears to be the default behaviour in this case --- when what should happen when the optimiser "gives up" is that it should just translate the code verbatim.

[deleted]
Post reply on HN