← Back to context

Comment by lelanthran

5 hours ago

> The point of the post is to say it's not possible to avoid them. Or at least, no human since the invention of C in 1972 has.

What are you talking about? UB was coined only in the first C standard, in 1989. Prior to that there was no "If you do this, anything can happen". It was "If you do this, that will happen".

More like, "if you do this, what happens depends on your particular combination of hardware, operating system, and compiler. Don't ask us."

  • No, that would be implementation defined.

    • The post I was replying to said,

      > UB was coined only in the first C standard, in 1989. Prior to that there was no "If you do this, anything can happen".

      I.e., the context is, before UB existed as a concept, how would these things be categorized. And I was trying to offer the correction that, before UB existed, it wasn't "all behavior is defined" but rather many behaviors depend on your particular local environment. While that may technically be implementation defined, the current standard requires that implementation defined be documented, and UB-like edge cases were most definitely not documented anywhere consistently in the old days!

    • No, that's actually UB. The important bit here is "compiler defined" -- UB means the compiler is allowed to assume it never happens while compiling.

      Consider, for example, an implementation defined function f() -- which can also diverge/crash horribly, etc.

      If I write

          if p {
            print("p is true")
          } else {
            g()
          }
      
          if p {
            f()
          }
      

      Then either we: - print p is true and execute f - do nothing

      This is true regardless of if f immediately crashes the computer, nasal demons, whatever -- that's implementation defined.

      UB means f may never happen.

      And that means the compiler may optimize this to just:

          g()
      

      Notice the difference here -- the print never happens!, and g always happens.

      You can see why this is concerning when you write code like

          if dry_run {
            print("would run rm -rf /")
          } else {
            run("rm -rf /")
          }
      
          if dry_run {
            // oops: some_debug_string is NULL and will segfault!
            print(some_debug_string);
          }

      1 reply →