Live data from Hacker News

Undefined Behavior in C and C++ (2024)

russellw.github.io

81–90 of 234 posts

Re: Undefined Behavior in C and C++ (2024)

#81
post #8

Earlier quoted context omitted.

Advantages of C are short compilation time, portability, long-term stability, widely available expertise and training materials, less complexity. IMHO you can today deal with UB just fine in C if you want to by following best practices, and the reasons given when those are not followed would also rule out use of most other safer languages.

This is a pet peeve, so forgive me: C is not portable in practice. Almost every C program and library that does anything interesting has to be manually ported to every platform. C is portable in the least interesting way, namely that compilers exist for all architectures. But that's where it stops.

Back in the 2000's I had lots of fun porting code across several UNIX systems, Aix, Solaris, HP-UX, Red-Hat Linux.

A decade earlier I also used Xenix and DG/UX.

That is a nice way to learn how "portable" C happens to be, even between UNIX systems, its birthplace.

Re: Undefined Behavior in C and C++ (2024)

#82

Earlier quoted context omitted.

Pointer provenance already existed before, but the standards were contradictory and incomplete. This is an effort to more rigorously nail down the semantics. i.e., the UB already existed, but it was not explicit had to be inferred from the whole text and the boundaries were fuzzy. Remember that anything not explicitly defined by the standard, is implicitly undefined. Also remember, just because you can legally constr…

Pointer provenance was certainly not here in the 80s. That's a more modern creation seeking to extract better performance from some applications at a cost of making others broken/unimplementable. It's not something that exists in the hardware. It's also not a good idea, though trying to steer people away from it proved beyond my politics.

It very much is something that exists in hardware. One of the major reasons why people finally discovered the provenance UB lurking in the standard is because of the CHERI architecture.

Re: Undefined Behavior in C and C++ (2024)

#83

Earlier quoted context omitted.

Pointer provenance was certainly not here in the 80s. That's a more modern creation seeking to extract better performance from some applications at a cost of making others broken/unimplementable. It's not something that exists in the hardware. It's also not a good idea, though trying to steer people away from it proved beyond my politics.

I'm not a compiler writer, but I don't know how you would be able to implement any optimization while allowing arbitrary pointer forging and without whole-program analysis.

Why? What specific optimization do you have in mind that prevents me from doing an aligned 16/32/64-byte vector load that covers the address pointed to by a valid char*?

Re: Undefined Behavior in C and C++ (2024)

#84
post #56

Earlier quoted context omitted.

> As shitty as C++ is from today's PoV, the entire gaming industry switched over within around 3 years towards the end of the 90s. Did they? What's your evidence? Are you including consoles? Btw, the alternatives in the 1990s were worse than they are now, so the bar to clear for eg C or C++ were lower.

I was there Gandalf... ;) Console SDKs offering C or C++ APIs doesn't really matter, because you can call C APIs from C++ just fine. So the language choice was a team and engine developer decision, not a platform owner decision (as it should be). From what I've seen, around the late mid-90's, C++ usage was still rare, right before 2000 it was already common and most middleware didn't even offer C APIs anymore. Of cou…

As another Gandalf, Playstation 2 was the very first console to actually offer proper C++ tooling.

That would be 2000, until then Sega, Nintendo and Playstion only had C and Assembly SDKs, even the Playstation Yaroze for hobbists did get released only with C and Assembly support.

PC was naturally another matter, especialy with Watcom C/C++.

Re: Undefined Behavior in C and C++ (2024)

#85

Earlier quoted context omitted.

Pointer provenance already existed before, but the standards were contradictory and incomplete. This is an effort to more rigorously nail down the semantics. i.e., the UB already existed, but it was not explicit had to be inferred from the whole text and the boundaries were fuzzy. Remember that anything not explicitly defined by the standard, is implicitly undefined. Also remember, just because you can legally constr…

Pointer provenance was certainly not here in the 80s. That's a more modern creation seeking to extract better performance from some applications at a cost of making others broken/unimplementable. It's not something that exists in the hardware. It's also not a good idea, though trying to steer people away from it proved beyond my politics.

> It's not something that exists in the hardware

This is sort of on the one hand not a meaningful claim, and then on the other hand not even really true if you squint anyway?

Firstly the hardware does not have pointers. It has addresses, and those really are integers. Rust's addr() method on pointers gets you just an address, for whatever that's worth to you, you could write it to a log maybe if you like ?

But the Morello hardware demonstrates CHERI, an ARM feature in which a pointer has some associated information that's not the address, a sort of hardware provenance.

Re: Undefined Behavior in C and C++ (2024)

#86

I don’t buy the “it’s because of optimization argument”. And I especially don’t buy that UB is there for register allocation. First of all, that argument only explains UB of OOB memory accesses at best. Second, you could define the meaning of OOB by just saying “pointers are integers” and then further state that nonescaping locals don’t get addresses. Many ways you could specify that, if you cared badly enough. My fa…

> nonescaping locals don’t get addresses inlining, interprocedural optimizations. For example, something as an trivial accessor member function would be hard to optimize.

Safer languages manage similar optimizations without having to rely on UB.

Re: Undefined Behavior in C and C++ (2024)

#88
post #83

Earlier quoted context omitted.

I'm not a compiler writer, but I don't know how you would be able to implement any optimization while allowing arbitrary pointer forging and without whole-program analysis.

Why? What specific optimization do you have in mind that prevents me from doing an aligned 16/32/64-byte vector load that covers the address pointed to by a valid char*?

Casting a char pointer to a vector pointer and doing vector loads doesn't violate provenance, although it might violate TBAA.

Regarding provenance, consider this:

  void bar();
  int foo() {
    int * ptr = malloc(sizeof(int));
    *ptr = 10;
    bar();
    int result = *ptr;
    free(ptr);
    return result;
  }
If the compiler can track the lifetime of the dynamically allocated int, it can remove the allocation and covert this function to simply

  int foo() { 
      bar();
      return 10;
  }
It can't if arbitrary code (for example inside bar()) can forge pointers to that memory location. The code can seem silly, but you could end up with something similar after inlining.

Re: Undefined Behavior in C and C++ (2024)

#89
post #86

Earlier quoted context omitted.

> nonescaping locals don’t get addresses inlining, interprocedural optimizations. For example, something as an trivial accessor member function would be hard to optimize.

Safer languages manage similar optimizations without having to rely on UB.

Well, yes, safer languages prevent pointer forging statically, so provenance is trivially enforced.

And I believe that provenance is an issue in unsafe rust.

Re: Undefined Behavior in C and C++ (2024)

#90
post #59

Earlier quoted context omitted.

Rust encourages a rather different "high-level" programming style that doesn't suit the domains where C excels. Pattern matching, traits, annotations, generics and functional idioms make the language verbose and semantically-complex. When you follow their best practices, the code ends up more complex than it really needs to be. C is a different kind of animal that encourages terseness and economy of expression. When…

Pattern matching should make the language less verbose, not more. (Similar for many of the other things you mentioned.) > When you know what you are doing with C pointers, the compiler just doesn't get in the way. Alas, it doesn't get in the way of you shooting your own foot off, too. Rust allows unsafe and other shenanigans, if you want that.

> Pattern matching should make the language less verbose, not more.

In the most basic cases, yes. It can be used as a more polished switch statement.

It's the whole paradigm of "define an ad-hoc Enum here and there", encoding rigid semantic assumptions about a function's behaviour with ADTs, and pattern matching for control-flow. This feels like a very academic approach and modifying such code to alter its opinionated assumptions isn't funny.

Post reply on HN