Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

511–520 of 748 posts

Re: Everything in C is undefined behavior

#511

Earlier quoted context omitted.

Volatile is a type system hack. They should have done a more principled fix, and certainly modern languages should not act as though "C did it" makes it a good idea. The reason for the hack is that very early C compilers just always spill, so you can write MMIO driver code by setting a pointer to point at the MMIO hardware and it actually works because every time you change x the CPU instruction performs a memory wri…

> The reason for the hack is that very early C compilers just always spill, so you can write MMIO driver code by setting a pointer to point at the MMIO hardware and it actually works because every time you change x the CPU instruction performs a memory write. Source?

This is one of those "everyone doing this kind of work knows" that's rather hard to source, but: this is basically the point of volatile. Especially for reads rather than writes, where you may want to read some location that is being written into by a different piece of hardware.

People used to use it for thread synchronization before proper memory barrier primitives (see https://mariadb.org/wp-content/uploads/2017/11/2017-11-Memor... ) were available. It was not entirely reliable for this purpose.

Re: Everything in C is undefined behavior

#512

I have never in my 20 years of writing C heard so much about undefined behavior as I have in the past 6 months on Hacker News. It has never entered the conversation. You write the code. If it doesn't work, you debug it and apply a fix or a workaround. Why does the idea of undefined behavior in C get to the front page so consistently?

I have the opposite experience, so many subtle bugs that bite you only on specific scenarios, so much that I can't count.

Re: Everything in C is undefined behavior

#513
post #337

Earlier quoted context omitted.

It isn't 1970 anymore. You can get 32-bit ARM MCUs with tens of kilobytes of flash and multiple kilobytes of RAM for less than 10 cents. We've long since reached a point where chips are cheap enough to be disposable. They are included in paper transit tickets and price tags. There is basically no market left where your volume is small enough that custom application-specific ICs aren't an option, but your volume is la…

> It isn't 1970 anymore. You can get 32-bit ARM MCUs with tens of kilobytes of flash and multiple kilobytes of RAM for less than 10 cents. Do they run at single-digit nA current draw?

You always could find deep niche where any high-level technology is not suitable.

I don't think you will program such device in C, rather in assembly, right? When you have like memory for 500 commands, it is easier to go directly to assembler, anyway, with such hardware as a target you don't need portability, this code is 100% hardware-dependable, at it is perfectly Ok.

BTW, which uC your have in mind when you talk about single-digit nA draw (in running state? in deep sleep?), because old 8-bit architectures typically are designed for older node processes and not as energy effective as new one, and draw in sleep doesn't depend much on RAM or FLASH size or architecture, it is more design philosophy.

Anyway, PIC16LF (20nA in deep sleep) or 8051 clone (50nA in deep sleep) or STM8 (~0.30 uA in halt) or ATtinys (100nA in deep sleep), which are covered by "768 bytes of flash and 64 bytes of RAM" description are comparable with EFM32 ARM32-M0+ (20nA in deep sleep), same with uA/Mhz, but ARM32-M0+ will do much more work for each Mhz, so it will be more efficient in the end (faster does all work and go to sleep again).

Re: Everything in C is undefined behavior

#514
post #447

Earlier quoted context omitted.

You're missing the point. Volatile forces two loads of a value that may have changed in the middle. So the value of "x" may depend on the time/order of load.

Why is that missing the point? Loading it twice, possibly with different values, is the intended behavior. It's only undefined because the C spec doesn't specify the order of the loads (unlike most other languages which have a perfectly well-defined order for side effects in a single expression).

What you are describing is implementation defined behavior. Using that is perfectly safe and reasonable. Undefined means this programs is malformed.

Re: Everything in C is undefined behavior

#515
post #173

Earlier quoted context omitted.

The problem is when you accidentally write an infinite loop. In a different language, you run the code, see that it gets stuck and fix it. In C, the compiler may delete the function, making it hard to realize what is happening.

This is not a problem that C or C++ programmers actually encounter, ever.

I actually encountered it a couple weeks ago.

Can you spot the infinite loop in this function?

  char* strcpy(char* restrict d, const char* restrict s) {
    stpcpy(d, s);
    return d;
  }
I'll help. A call to `stpcpy` that ignores the return value can be swapped with a call to the (more likely to be optimized) `strcpy`. Since that's infinite recursion, and there is no forward progress, it's undefined behavior and anything goes.

This isn't just theory, it actually broke things in practice for me.

Re: Everything in C is undefined behavior

#516
post #191

Earlier quoted context omitted.

Yes? I agree with that. I don't really see the issue there. The computer will allocate data in aligned addresses, so you would have to be doing something weird to begin with to access unaligned pointers. And aligned access is always better anyway. I guess packed structs are a thing if you're really byte golfing. Maybe compressed network data would also make sense. But then I would assume you are aware of unaligned po…

String search algorithms would be one example, where a 64-bit register can be used as a “vector” containing 8x1 bytes.

Where is the part about unaligned pointers?

Re: Everything in C is undefined behavior

#517
It's also worth highlighting that C is perhaps the most officially standardized programming language in history.

What a contradiction. Strong evidence that standard-driven programming language development is much worse than implementation-driven development. Standards should be used for data types and external interfaces/protocols, not programming languages.

Re: Everything in C is undefined behavior

#518

Earlier quoted context omitted.

> 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.

Re: Everything in C is undefined behavior

#519
post #113

Yes there is tons of surprising and weird UB in C, but this article doesn't do a great job of showcasing it. It barely scratches the surface. Here's a way weirder example: volatile int x = 5; printf("%d in hex is 0x%x.\n", x, x); This is totally fine if x is just an int, but the volatile makes it UB. Why? 5.1.2.4.1 says any volatile access - including just reading it - is a side effect. 6.5.1.2 says that unsequenced…

Volatile is a type system hack. They should have done a more principled fix, and certainly modern languages should not act as though "C did it" makes it a good idea. The reason for the hack is that very early C compilers just always spill, so you can write MMIO driver code by setting a pointer to point at the MMIO hardware and it actually works because every time you change x the CPU instruction performs a memory wri…

Thr Linux kernel uses READ_ONCE and WEITE_ONCE which look like actual function calls which is very sensible.

Re: Everything in C is undefined behavior

#520

Earlier quoted context omitted.

What should the behavior above be defined to do?

“Implementation defined behaviour”: compiler author chooses, and documents the choice. A lot of UB should be implementation defined behaviour instead; this would much better match programmers’ intuitions as they reason about their code - you can even see it in the comments of this post: it’s always things like “this hardware supports / doesn’t support unaligned accesses”, it’s never nasal demons.

I told someone at a conference that UB actually means "implementation-defined, no documentation required". He started to refute me and then stopped.
Post reply on HN