Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

361–370 of 748 posts

Re: Everything in C is undefined behavior

#361

Earlier quoted context omitted.

> If they do, that is no longer an implementation of C. This is plain wrong. Undefined behaviour, means the C standard specifies no restriction on the behaviour of the program, which is what the implementation chooses to emit. An implementation can very well choose to emit any program it pleases, including programs that encrypt your harddisk, but also programs that stick to well defined rules.

Sure, but the point is that code written against such a compiler is not C and is not portable. It is written in a dialect of C, and that comes with drawbacks. Writing C (or any language) means adhering to the standard, because that's the definition of the language.

You can't make any useful software in "Portable C" - or any portable language for that matter.

Side effects matter, and they are always non-portable/implementation defined/dependent on the hardware.

What printf() actaully does is implementation defined - what does "printing mean", does a console even exist? Maybe a user expects it to show graphical ascii/utf8 glyphs on a LCD display? Well, not every computer has that, so now what?

Re: Everything in C is undefined behavior

#363

Earlier quoted context omitted.

however you certainly can do that. The point of unaligned is the hardware can't load it from a single memory location in one address. It needs two accesses. And in that time, the value of one of the two addresses that the hardware has to load can change. I would hope you're not so stupid as to design hardware that relies on this, but the fact is it certainly is possible for someone to do that. And if you do that, the…

Yeah, the unaligned accesses aren't going to be atomic unless the hardware supports it. > And in that time, the value of one of the two addresses that the hardware has to load can change. You mean volatile addresses that could spontaneously change in the middle of the reads? Like memory mapped I/O addresses? I would expect these to have stricter access requirements than arbitrary general purpose memory locations. > I…

> Anything that does that is broken and terrible anyway

which is why it is undefined behaviour. the optimizer writers have told me consistently that if they can assume you're not doing this thing that's stupid anyway, they can make my code faster. And since I'm not doing that stupid thing anyway, I want my code to be faster.

Re: Everything in C is undefined behavior

#364
post #341
post #328

Earlier quoted context omitted.

When compiler decides something is UB aka "result of this code is not defined and could be any" it selects the most performant version of undefined behavior - doing nothing by optimizing code away.

The compiler is not free to remove accesses to something marked volatile - its defined as a side-effect. Volatile means something else may be acting here. Something else may install anything into the register at any time - and every time you access. The compiler is required to preserve the order of accesses. In almost every C compiler, today, there are almost no optimisations the moment a volatile is introduced, for…

If code has undefined behavior, the entire execution path that leads to that UB has no assigned semantics in the C model. So there are no volatile accesses in this code according to the C abstract machine - the entire execution path is UB, so it can be assumed it doesn't happen at all.

Re: Everything in C is undefined behavior

#365

Earlier quoted context omitted.

And it makes sense as long as you allow the concept of unsequenced operations at all (admittedly it’s somewhat rare; e.g. in Scheme such things are defined to still occur in sequence, but which specific sequence is unspecified and potentially different each time). The “volatile” annotation marks your variable as being an MMIO register or something of that nature, something that could change at any point for reasons o…

Your first paragraph makes it sound as if the compiler will actually generate two reads of the value of some register, which might lead to unexpected effects at runtime for certain special registers. However, this is not at all what UB means in C (or C++). The compiler is free to optimize away the entire block of code where this printf() sequence occurs, by the logic that it would be UB if the program were to ever re…

> Your first paragraph makes it sound as if the compiler will actually generate two reads of the value of some register, which might lead to unexpected effects at runtime for certain special registers.

I don’t see how. I was trying to explain why it’s reasonable for a volatile read to be a side effect, after which the C rule on unsequenced side effects applies, yielding UB as you say.

Re: Everything in C is undefined behavior

#366

The UB in unaligned pointers is even worse: an unaligned pointer in itself is UB, not only an access to it. So even implicit casting a void*v to an int*i (like 'i=v' in C or 'f(v)' when f() accepts an int*) is UB if the cast pointer is not aligned to int. It is important to understand that this is a C level problem: if you have UB in your C program, then your C program is broken, i.e., it is formally invalid and wron…

The problem with C UBI is that originally it meant the compiler has the freedom to map your code to the hardware inspite of machine instructions differing slightly between one another. The same C program may express different behaviour depending on which architecture it is running on.

This type of UB is fine and nobody really complains about hardware differences leading to bugs.

However, over time aggressive readings of UB evolved C into an implicit "Design by Contract" language where the constraints have become invisible. This creates a similar problem to RAII, where the implicit destructor calls are invisible.

When you dereference a pointer in C, the compiler adds an implicit non-nullable constraint to the function signature. When you pass in a possibly nullable pointer into the function, rather than seeing an error that there is no check or assertion, the compiler silently propagates the non-nullable constraint onto the pointer. When the compiler has proven the constraints to be invalid, it marks the function as unreachable. Calls to unreachable functions make the calling function unreachable as well.

Re: Everything in C is undefined behavior

#367
post #299

Earlier quoted context omitted.

Fair enough! > And if it's not succeeded for 54 years, "try harder", or "just never make a mistake", is at least not the solution. And I 100% agree. UB is way overused by these standards for how dangerous it is, and as a consequence using C (and C++) for anything nontrivial amounts to navigating a minefield.

What should the behavior above be defined to do?

Couldn’t you just define that function arguments are evaluated left to right?

Or just throw an error.

Re: Everything in C is undefined behavior

#368

Earlier quoted context omitted.

> If they do, that is no longer an implementation of C. This is plain wrong. Undefined behaviour, means the C standard specifies no restriction on the behaviour of the program, which is what the implementation chooses to emit. An implementation can very well choose to emit any program it pleases, including programs that encrypt your harddisk, but also programs that stick to well defined rules.

Sure, but the point is that code written against such a compiler is not C and is not portable. It is written in a dialect of C, and that comes with drawbacks. Writing C (or any language) means adhering to the standard, because that's the definition of the language.

Maybe it’s a generation thing. Languages like ML and Lisp have many implementations, while newer languages like Perl and Python are steered by a single organization. It’s way easier for the latter to have a single source of truth.

The C standard reminds me of Posix. You have a rough guideline if you ever wanted to port a program, but you actually have to learn the new compiler and its actual behavior before doing so.

Re: Everything in C is undefined behavior

#369
post #299

Earlier quoted context omitted.

Fair enough! > And if it's not succeeded for 54 years, "try harder", or "just never make a mistake", is at least not the solution. And I 100% agree. UB is way overused by these standards for how dangerous it is, and as a consequence using C (and C++) for anything nontrivial amounts to navigating a minefield.

What should the behavior above be defined to do?

Print x twice. Not all “side effects” care about order.

Better yet, define an order for parameter evaluation.

Post reply on HN