Re:Why should I have written ZeroMQ in C, not C++ (2012)
by saagarjha on Thursday December 13, 2018 @07:08AM
(#18671704)
I’m not sure I follow your description of undefined behavior, which seems to me to deviate from the standard’s? Correct me if I’m wrong, but to me it seems like you’re saying something along the lines of “the C standard ‘expects’ that null dereferences fault, and ‘assumes’ division by zero to trap; it is impossible to write a standards compliant compiler for architectures where this is not true”. If so, let me know an I’ll explain why I disagree; otherwise, it would be nice if you could clarify what you actually meant.
Yeah, the "C abstract machine" that most C-like languages rely on by the fact of relying on libraries like libc.
> Because it doesn’t actually define anything in this case.
To be clear, when I said expect, I meant expect. These languages expect invalid dereferences to fault—i.e. to cause control flow to be taken out of the program's hands. Which is to say, they expect a generated dereferencing instruction that returns to have put the system into a valid state.
But in practice, what that means is that compilers just expect dereferences to always be valid (because any dereference that returns is valid.) So they don't have to generate any check for null before doing a dereference; and they don't have to worry about having any way to represent the result of a null dereference.
Another way to say that is that dereferencing null pointers is implicit undefined behavior. There's no part of the spec that covers what would happen if you dereferenced a null pointer, because in the model as the spec lays it out, dereferencing is a happy, clean little operation that never goes wrong. (i.e. "The MMU might cause a CPU fault? Who cares! My program didn't cause that fault; it was the MMU's choice to decline to read from $0. Other MMUs could totally allow that, and then LEA would be defined for the entire domain.") Same goes for reading from unmapped regions—"it's the MMU's fault; it could have just as well returned 0, after all."
> I’m sure that in these cases the compiler doesn’t literally insert checks
Yep, you're right. Again, it's because this is what these languages expect. It's not quite the same as undefined behavior; it's that the "C abstract-machine evaluation model" was defined to assume that architectures will always have their IDIV-equivalent instruction fault if invalid. If it returns a flagged value on some arch instead, that's something the C evaluation model is not prepared to deal with.
(Technically, I believe that you'd say that a C compiler "cannot be written" for such an arch while retaining conformance to any existing C standard, and for such an arch to gain a conformant C compiler, a new C standard draft would have to be written that specifies an evaluation model for such architectures—as then the compiler could at least be conformant to that.)
Which is helpful to know: just compiling C for such an arch at all, is undefined behavior, no matter what you write ;)