Live data from Hacker News

The Problem with Friendly C

blog.regehr.org

31–40 of 174 posts

Re: The Problem with Friendly C

#31
post #25
post #17

Earlier quoted context omitted.

Undefined behaviour has meant undefined behaviour. That doesn't mean nasal demons. That means this: Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the i…

the Standard imposes no requirements on undefined behaviour. The list you quoted is informative, to give us a basic idea what to possibly expect, not a list of things we may rely upon. Rejecting translation outright aside, undefined behaviour is the strongest language the standard uses for illegal constructs. I do not see it as undefined in the sense of lacking a common definition (eg is 0 a natural number, or not) b…

Well I submit that as a simple question of quality of implementation, implementers should try their hardest to go for the something that behaves "in a documented manner characteristic of the platform"! But instead, they seem to pick something else. And I claim that this is not helpful to their users, who would be far better served by the characteristic-of-the-platform option.

Re: The Problem with Friendly C

#32
post #5

How exactly would performance degrade by defining a virtual machine for C programs to run in where assurances are given that all of the standard behavior is fully defined -this operation either fails, or gives THIS result-? It sounds like it could be massively useful, at least for non-realtime applications.

Let's say you have a trapping division on the actual CPU you run on. And let's say the virtual machine specifies that division doesn't trap. Then the compiler has to insert checks for invalid inputs to prevent trapping from happening. Those checks may degrade performance.

Re: The Problem with Friendly C

#33
post #6
post #3

If ((uint32_t)x But why can't it just produce something different on each system? Allow me to call it as I see it: the modern interpretation of undefined behaviour is bullshit. What compilers do today should be the recourse of absolute last resort, and the sort of thing that makes its authors feel bad. But it seems to be treated as a matter of course. I don't know what to say. Mandatory reading: http://robertoconcert…

The, to me, obvious thing to do with code with undefined behaviour is to emit an error and refuse to compile it. Programmers should never rely on undefined behaviour. Then again, I think languages shouldn't have undefined behaviour and that programmers who use languages with undefined behaviour deserve what they get.

The problem, as Regehr (the author of this submission) has pointed out many times before, is more subtle than that. Because certain behavior is considered undefined, compilers are allowed to assume the code it is compiling is well defined, and optimize accordingly. That can cause simple bugs to have mysterious effects. For example:

    a->thing = 42;
    if (a == NULL) {
      return;
    }
Obviously that code is wrong; I should check for NULL before using a. But because I dereferenced a, the compiler can assume a must not be NULL, and just removes the null check as dead code. This scenario has caused problems in the kernel, and made bad bugs even worse.

Re: The Problem with Friendly C

#34
post #20
post #14

Earlier quoted context omitted.

Apparently a (uint32_t) shifted by 32 is license to become completely insane. int main(int argc, char **argv) { uint32_t x = (uint32_t)0x12345678

I am almost LOLing at the segmentation fault. Where the fuck does a segmentation fault come from? It's shifting a value . Utterly mystifying.

Looking at the generated instructions might give a clue, but I'm just as mystified. Given the size of the program, I doubt there's much of it to inspect anyway.

Re: The Problem with Friendly C

#35
post #12

I think the most important point of Friendly C is not to define the behaviour for what would otherwise be undefined, but to define a behaviour; from this point of view, it would be unnecessary to argue over the examples he mentions like memcpy() vs memmove() and integer shifting --- it only suffices that every implementation define the behaviour, and what that behaviour precisely is can differ between them. A lot dif…

You have to look deeper for the OOB array access question. For example, imagine I have code like this: if (a > 1) b++; array[b] = 0; c = a + 10; Under your suggested semantics, can the compiler use the value loaded from `a` at the point of the if() statement to calculate `a + 10`? Or does it have to emit a reload of `a` after the array access, in case `array[b]` was an OOB access that overwrote `a`?

How about treating it just like another thread accessing the values? So yes in the general case, no if you put in memory barriers or atomics.

Re: The Problem with Friendly C

#36
post #31
post #25

Earlier quoted context omitted.

the Standard imposes no requirements on undefined behaviour. The list you quoted is informative, to give us a basic idea what to possibly expect, not a list of things we may rely upon. Rejecting translation outright aside, undefined behaviour is the strongest language the standard uses for illegal constructs. I do not see it as undefined in the sense of lacking a common definition (eg is 0 a natural number, or not) b…

Well I submit that as a simple question of quality of implementation, implementers should try their hardest to go for the something that behaves "in a documented manner characteristic of the platform"! But instead, they seem to pick something else. And I claim that this is not helpful to their users, who would be far better served by the characteristic-of-the-platform option.

It's really friction between incompatible visions of C: Some want it to be a portable wrapper over assembler with predictable semantics, others want it to run as fast as possible.

Like it or not, the standard leaves the doorway open for the latter group to come up with increasingly aggressive optimization, only limited by their ingenuity.

Re: The Problem with Friendly C

#37

Earlier quoted context omitted.

I think the problem is that some of these optimizations aren't just compiler makers being greedy, they're actually a huge benefit. IMO what's missing is the ability to mark areas "unsafe" -- IE, tell the compiler "it's ok to take advantage of certain optimizations here" while marking other areas "please don't goof with this" (ie, security critical code). You can kind of do this with pragmas, but not really. Here's a…

For example, knowing that INT_MAX+1 is undefined allows optimizing "X+1 > X" to "true". If a programmer writes "X+1 > X", chances are this is an overflow check. Doing this is perfectly defined by the standard if X is an unsigned integer, but not if it's signed. That's what doesn't make sense, since they could've made the unsigned case undefined as well. which allows a broad range of loop optimizations to kick in What…

> What sort of optimisations exactly, and just how significant are they?

Well, if you could remove one instruction per loop on most computers (especially conditionals that could cause a branch mis-prediction), the effect of that in terms of performance is pretty staggering. Instead of thinking of it as an optimization, think of it as a check that doesn't need to be inserted into the code. If you can tell the compiler "I promise I won't overflow this variable", that's a lot less error checking it needs to insert on every iteration.

> I don't believe C should be a language where the compiler does all sorts of high-level optimisation; it should be a straightforward "do what I say" type of language where you get almost exactly what you write

Well, you could just compile with -O0 then. I don't necessarily agree with C on this, but it's pretty clear the community has made the decision to prioritize speed over safety. Nothing wrong with that, but if safety is your priority you should probably look at things other than C. Even if you were to define undefined behavior, it's a spectacularly dangerous language.

Re: The Problem with Friendly C

#39
post #12

I think the most important point of Friendly C is not to define the behaviour for what would otherwise be undefined, but to define a behaviour; from this point of view, it would be unnecessary to argue over the examples he mentions like memcpy() vs memmove() and integer shifting --- it only suffices that every implementation define the behaviour, and what that behaviour precisely is can differ between them. A lot dif…

You have to look deeper for the OOB array access question. For example, imagine I have code like this: if (a > 1) b++; array[b] = 0; c = a + 10; Under your suggested semantics, can the compiler use the value loaded from `a` at the point of the if() statement to calculate `a + 10`? Or does it have to emit a reload of `a` after the array access, in case `array[b]` was an OOB access that overwrote `a`?

I'd say that it doesn't have to read 'a' again because these are separate variables and there's no requirement for 'a' and 'array' to be contiguous, or for that matter 'a' being in memory at all instead of just being in a register. An OOB access could overwrite the memory storing 'a', but I think this case of relying on the ordering and location of objects in memory is just not something any C code would ever have to do.

Re: The Problem with Friendly C

#40
I applaud the author for reaching the daunting part of this project and reacting with humility appropriate to the difficulty. I hope they continue in this effort, because they sound like the right person for the job.

There are going to be a lot of trade offs in any friendly C spec. Appreciation for both sides of a trade off is valuable in making good decisions.

Post reply on HN