Live data from Hacker News

Undefined behavior in C is a reading error

yodaiken.com

251–260 of 503 posts

Re: Undefined behavior in C is a reading error

#251
post #228

Earlier quoted context omitted.

"undefined behavior can be ignored" (meaning: the case where this could overflow need not be considered and can be treated as though it does not exist) vs "The implementation doesn't have to take notice of the fact that the behavior is undefined" strikes me as a distinction without a difference given that we land in exactly the same spot: the standard allows us to treat "for (int i=param; i > An implementation might…

Of course an implementation can do anything it likes, including defining the behavior. That's one of the infinitely many ways of handling it -- precisely because it's undefined behavior . I'm not using "undefined behavior" as the English two-word phrase. I'm using the technical term as it's defined by the ISO C standard. "The construct has undefined behavior " and "this implementation defines the behavior of the cons…

> Of course an implementation can do anything it likes, including defining the behavior. That's one of the infinitely many ways of handling it -- precisely because it's undefined behavior.

An implementation can do whatever it likes within the proscribed bounds the standard provides for reacting to "undefined behavior", and conversely whatever the implementation chooses to do within those bounds is consistent with the standard.

Which, again, is the entire point of this: "the loop iterates exactly 16 times" is a standards-conforming interpretation of the code in question. There's nothing outside the standard or non-standard about that. That is, in fact, exactly what the standard says that it is allowed to mean.

> I'm not using "undefined behavior" as the English two-word phrase. I'm using the technical term as it's defined by the ISO C standard.

So am I. Unlike you, I'm merely taking into account the part of the standard that says "NOTE: Possible undefined behavior ranges from ignoring the situation completely with unpredictable results..." and acknowledging that things that do so are standards-conforming.

> You seemed to be suggesting that "ignoring the situation completely" would result in the loop iterating exactly 16 tyimes.

I'm merely reiterating what the standard says: that the case in which the loop guard overflows can be ignored, allowing an implementation to conclude that the loop iterates exactly sixteen times in all scenarios it is required to consider.

All you seem to be doing here is reiterating, over and over again, "the standard says the behavior of the loop is undefined" to argue that the loop has no meaning, while ignoring that a different page of the same standard actual gives an allowable range of meanings to what it means for "behavior to be undefined", and that therefore anyone of those meanings is, in fact, precisely within the bounds of the standard.

We can validly say that the standard says "for (int i=param; i < param + 16; i++)" means "iterate 16 times always". We can validly say that the standard says "for (int i=param; i < param + 16; i++)" means "launch angband when param + 16 exceeds MAX_INT". Both are true statements.

Re: Undefined behavior in C is a reading error

#252
post #135

Earlier quoted context omitted.

The world doesn't end, but in the "int" case you get nice vector code and in the "unsigned int" case you get much less nice scalar code: https://gcc.godbolt.org/z/cje6naYP4

Yes, that is true. The proper way for a compiler to handle this, would be to add a single overflow check before the loop, which branches to a scalar translation of the loop. Most realistic code will need a scalar version anyway, to deal with the prolog/epilog of the unrolled loop for iteration counts that aren't multiples of the unrolling factor. Surely you agree that treating unsigned overflow differently from signe…

> The proper way for a compiler to handle this, would be to add a single overflow check before the loop, which branches to a scalar translation of the loop. Most realistic code will need a scalar version anyway, to deal with the prolog/epilog of the unrolled loop for iteration counts that aren't multiples of the unrolling factor.

That's true, I agree that that would be a clever way to handle this particular case. It would still happily invoke undefined behavior if the indices don't match the array's length, of course. Many assumptions about the programmer knowing what they are doing goes into the optimization of C code.

> Surely you agree that treating unsigned overflow differently from signed does not make any sense semantically?

Yes. Silently wrapping unsigned overflow is also very often semantically meaningless.

Re: Undefined behavior in C is a reading error

#253
To me the real problem is that compilers these days do too much. Nobody asked for these optimizations, if you want optimized code, use C++, or Rust, or whatever other "modern" language that has higher level constructs and thus can optimize the code better.

The reason to use C is to have an "high level assembler", and there is no reason to use C if I can't rely on the output of the compiler, and if the compiler eliminates some code that I write. We all know that happens when a signed integer overflows, we all know that most architectures are little endian, etc.

Even if something is "undefined behaviour" for the standard, it usually has some well defined behaviour on the platform that you are targeting.

Unfortunately, for these reasons gcc is dangerous to use, it's not a problem of desktop application (if it crashes, who cares), but I talk about critical systems. It would be unacceptable if a machine ends up killing someone because at gcc they though that they could remove a check that they thought it was useless. And so you have to spend thousand of $ just to get reliable compilers that doesn't do silly optimizations.

I think that they should make a sort of "gcc lite" that does exactly what (at least to me) a C compiler has to do: translate the code from C to assembly, without changing the semantic of the code. If there is an undefined behaviour that behaviour will be translated to the assembly code and you will let the processor to deal with it.

Also, we talk about optimizations that could be made by exploiting undefined behaviour, fine, but also the programmer usually optimizes exploiting the same undefined behaviours by hand.

Re: Undefined behavior in C is a reading error

#254

Earlier quoted context omitted.

> Like starting to optimize away loop checks that can "never happen" because signed integer overflow is UB, suddenly changing the behavior of programs that were fine for years? Yeah. Not doing that on modern processors is actually quite disruptive. Here: for(i = offset; i What C compilers currently do is, in line with the standard, ignore the case that offset + 16 might overflow. This makes this eligible for loop unr…

> minority use-case The amount of code that looks like this in a big enough hot loop to make a difference is negligible. Can you provide even one real-world example where this makes a difference, i.e. not some microbenchmark? The amount of code that can break as a result of signed overflows being UB, on the other hand, is huge. > programmers would have to do a lot more fragile hand-unrolling of operations to get that…

> The amount of code that can break as a result of signed overflows being UB, on the other hand, is huge

C++ recently decided to not make signed overflow defined, despite having the explicit opportunity to do so. Here is the reasoning:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p090...

> Performance concerns, whereby defining the behavior prevents optimizers from assuming that overflow never occurs;

> Implementation leeway for tools such as sanitizers;

> Data from Google suggesting that over 90% of all overflow is a bug, and defining wrapping behavior would not have solved the bug.

Presumably, data from Google disproves your assertion that the amount of code that breaks due to signed overflow being UB is huge.

Re: Undefined behavior in C is a reading error

#255

Earlier quoted context omitted.

What you've written doesn't demonstrate the issue outlined in the big report. The issue is that real-world code defends against certain hostile inputs like so, and that the optimization breaks those defenses: int a,b,c; a=INT_MAX; /\* statement ONE */ b=a+2; /* statement TWO */ c=(b>a); /* statement THREE \*/ Whether or not you think this is technically permissible by a sufficiently self-serving (from the perspective…

If you want pragmatism, check whether something is legal before you do it.

This is addressed quite thoroughly in the thread that I linked. It is generally impossible to determine whether your code has a bug, and you cannot possibly be responsible for every bit of code that your code may happen to touch, but even if you could, mistakes and bad practices will happen. Practically speaking, it does not matter if you can find a way to displace blame onto the writer of the code. Placing blame is not how one minimizes harm. Maybe we have different definitions of pragmatism in our heads.

I would also say that leaving such a common occurrence as integer overflow as undefined behavior rather than to consider that it practically always has platform as implementation specific behavior doesn't make much sense. I mean, it does always have platform specific implementation, right? Does that not exclude it from the definition of undefined behavior? Genuinely curious.

The downvotes on my previous comments tell me this sort of thinking is endemic. I suddenly have more insight into the concern people have about software development as a field.

Re: Undefined behavior in C is a reading error

#256

Earlier quoted context omitted.

For your last point, the extent of UB driven changes to semantics is still not widely known in the programmer community. Programmers don't read the standard - they read K&R, and K&R is right now describing a different language. We've had 15 years of programmers repeatedly filing bug reports to be told that the expected, tested, relied on, behavior was ephemeral. Only very sophisticated projects figure out about UB. O…

So what optimizations do you mean with "these UB optimizations" then? And would it change your mind to see a benchmark proving the usefulness of that particular UB optimization?

e.g. assuming UB can't happen: deleting overflow or null pointer checks, deleting comparisons between pointers that are assumed to point at different objects, ...

Re: Undefined behavior in C is a reading error

#257

Earlier quoted context omitted.

The compiler is allowed to act as if this loop executes exactly 16 times. That means it could unroll and vectorize it for example.

It is completely useless to allow compilers to assume false things about the code they generate.

It’s not useless. The assumption is not false if the program doesn’t have undefined behavior. The assumption allows the code to be a few times faster. To disallow this assumption would inhibit these optimizations.

Re: Undefined behavior in C is a reading error

#258
post #107

I dislike how UB is used where unspecified would work. For instance overflowing arithmetic is well specified on every architecture - the behaviour may be different on say sparc vs an hc12 vs x86, but on any of those architectures it will always be the same. Yet compiler devs have instead decided that it is undefined and so can be treated however they like. There are so many of these UB that could be unspecified that…

The C++ committee recently (for the C++20 standard) voted against making signed overflow defined, opting to keep it undefined. Primarily for performance reasons (and because it would usually be a bug anyway).

www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r4.html#r0r1

You're of course free to disagree with the reasoning. But you'd probably agree that a new standard revision that forces the average application to become, say, 5% slower, just so that broken programs would be just as broken, would not be very well-received.

Re: Undefined behavior in C is a reading error

#259
post #211

Earlier quoted context omitted.

I would note that the article is explicitly contesting the definition of UB that you are giving here (though you are absolutely right that this is the de facto definition used by all major compilers, and the commtitee). Basically the article is arguing that UB should be similar to Unspecified behavior - behavior that the implementation leaves up to the hardware and/or OS. I'm not sure where I fall to this issue, thou…

from ISO/IEC 9899:2011 "Programming Languages -- C" 3.4.3 1 undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements 2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner charac…

To me ignore the situation completely with unpredictable results would mean: the compiler generates an assembly that could not be correct, and then the behaviour of the program is determined by what the processor does.

Doing something like removing checks is not ignoring the situation: is acting in some particular way when undefined behaviour is detected.

And it has neither unpredictable results: it specifies what happens, since these checks are added systematically.

I don't see anywhere in the standard that the compilers are free to change at their choice the semantic of the program if undefined behaviour is detected. Rather undefined means to me that the compiler generates code where the result cannot be known because it will depend on external factors (basically the hardware implementation).

Re: Undefined behavior in C is a reading error

#260

Earlier quoted context omitted.

> Something like 1 That is what implementation-defined behavior is for. Feel free to advocate for changing the standard accordingly.

> Feel free to advocate for changing the standard accordingly. I am, in fact, describing the existing C standard, not advocating for changes. Please refer to Annex L "Analyzability", which defines the terms I used: "bounded undefined behavior" and "critical undefined behavior". Note that this section is conditional... it is not widely adopted. I am advocating for increased adoption of this part of the standard, or ba…

You're right, apologies.
Post reply on HN