Reducing undefined behavior in the C language

(lwn.net)

30 points | by signa11 1 hour ago

7 comments

  • chasil 29 minutes ago
    "Some Honeywell machines, for example, had nine-bit bytes."

    OS 2200 has 36-bit words. It is still a supported platform.

    https://en.wikipedia.org/wiki/UNIVAC_1100/2200_series

    This platform was the first SMP UNIX implementation:

    "Any configuration supplied by Sperry, including multiprocessor ones, can run the UNIX system."

    https://www.nokia.com/bell-labs/about/dennis-m-ritchie/other...

  • 1vuio0pswjnm7 21 minutes ago
    1790620504 | Reducing undefined behavior in the C language | https://lwn.net/SubscriberLink/1095811/b9325731ea9b61e0/ | https://news.ycombinator.com/item?id=49882419 | 15 comments

    1790673092 | Reducing undefined behavior in the C language | https://lwn.net/SubscriberLink/1095811/efcdbcf080cfa4c6/ | https://news.ycombinator.com/item?id=49890290 | 0 comments

  • elais-dev 49 minutes ago
    i've seen static analyzers catch many ub patterns, but guaranteeing zero ub needs whole‑program analysis that blows up compile time and still produces false positives that drown developers
  • p1necone 46 minutes ago
    The concept of undefined behaviour specific to C/C++ has always seemed batshit insane to me, and I'm yet to read anything about it that has made it seem any less so.
    • Veserv 0 minutes ago
      Undefined behavior is just what happens when you violate a mandatory precondition.

      if (x > 0) {…}. But what if you are in the body and x <= 0?

      if (false) {…}. But what if you execute the body?

      These are “impossible”. What happens when the impossible occurs is “undefined”.

      When the older standards said signed integer overflow for addition is undefined what they are actually saying is that the real definition of + is:

          int +(int x, int y) { 
            assert(actual_math_add(x, y) <= signed_int_max);
            return machine_add(x, y);
          }
      
      So of course what happens when you get signed overflow is undefined, you should hit that assert and your program should explode and die.

      But, in the interest of performance, “release mode” (which in this case is just any compilation) elides asserts since as a programmer you should not write code that asserts in much the same way that you should not write assert(false) in a normal code path that is supposed to run.

    • nananana9 21 minutes ago
      It doesn't make sense to define what happens when you e.g. read from NULL because it's hardware specific - if you have virtual memory of some sort, you'd probably get a page mapping error. If you don't (embedded, WASM), you'd read back whatever value is at that address.

      Does Rust define what I get when I dereference NULL in unsafe code? I doubt it, since it would require a NULL check before every pointer dereference.

      The only insane thing about UB is that compiler writers took what everyone understand meant "the compiler emits what it emits and you get what you get" and turned it into "since it's undefined it means it can never happen so we can delete your null check".

    • mpyne 22 minutes ago
      It's not specific to C or C++, though it is more prominent there.

      Rust's unsafe mode, for instance, has undefined behavior. A whole list of them, in fact.

    • chasil 23 minutes ago
      It was written for a PDP-11 with 64k of RAM.

      There wasn't room for safe programming practices, and direct manipulation of the hardware was a design requirement.

      It assumes that you know what you are doing.

      There are also ports to the Zilog Z80, an architecture with similar limitations (UZI, FUZIX).

  • BeaverGoose 34 minutes ago
    Make signed overflow defined please.
    • _kst_ 9 minutes ago
      I disagree, though I wouldn't mind adding a mechanism to say that you want signed overflow to be well defined.

      C23 already requires 2's-complement representation for signed integer types, but signed overflow still has undefined behavior. I think that mandating 2's-complement wraparound would be a mistake.

      Some instances of undefined behavior can be detected at compile time. For example, if I write

          int too_big = INT_MAX + 1;
      
      a reasonably clever compiler can warn about it (and in fact both gcc and clang do so). If the result of INT_MAX + 1 were defined by the language to be INT_MIN, there would be no basis for such a warning.

      If you evaluate n + 1 and it's possible for n to be equal to INT_MAX before the addition what do you want the result to be? Would quietly yielding INT_MIN really be useful?

      Ideally, if I (accidentally) evaluate INT_MAX + 1, I'd like to be told that I've made a mistake. C doesn't have a good mechanism for doing so.

      gcc has a non-standard option "-fsanitize=signed-integer-overflow" that can be used to catch signed overflow at runtime. If signed overflow yielded a well defined result, that option would be non-conforming.

  • jdw64 36 minutes ago
    [dead]
  • jdw64 52 minutes ago
    [dead]