Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

301–310 of 748 posts

Re: Everything in C is undefined behavior

#301
post #231

Earlier quoted context omitted.

Intuitively yes - the program will be compiled as if B-inputs are never passed to the program, and that can include eliminating code that tries to detect B-inputs.

This is a description of an imaginary compiler, evoked by the ANSI/ISO standards documents, which has never existed and will never exist. To understand what the program will do, you just have to understand the compiler behavior on your target platforms. A helpful intuition pump is: imagine the ANSI/ISO specifications simply do not exist; now what? Well, you just continue your engineering practice, the way you would f…

GCC -O1 and clang -O1 will both optimize this function under the assumption that inputs that cause signed integer overflow are never passed:

    int will_overflow(int a, int b) {
        int sum = a + b;
        if (b > 0 && sum 

Re: Everything in C is undefined behavior

#302
post #126

Earlier quoted context omitted.

Okay, so Java compiles to machine code now? Because the last time I looked it appeared to need some godawful slow bytecode interpreter that took up thousands of kilobytes of RAM.

If you don't like JIT/JVM there's GraalVM Native Image. https://www.graalvm.org/latest/reference-manual/native-image... In the past you could use e.g. Excelsior JET.

Great, can you fit it into 768 bytes of flash and 64 bytes of RAM?

Re: Everything in C is undefined behavior

#303
post #182

Earlier quoted context omitted.

Yes, there is a data race there. The value of a volatile can be changed by something outside the current thread. That’s what volatile means and why it exists. Edit: thread=thread of execution. I’m not making a point about thread safety within a program.

Not sure why you're being downvoted. That's completely right. The example is silly. The code is obviously bad, doesn't matter if it's UB or not. I'm also not convinced (yet) that the example really is UB: I agree reading a volatile is "a side effect" in some sense, and GP cited a paragraph that says just that. But GP doesn't clearly quote that it's a side effect on the object (or how a side effect on an object is def…

The problem is that the function call as a whole is UB. Having the original example compile to the equivalent of

  volatile int x;
  int a = x;
  int b = x;
  printf("%x %d\n", a, b);
is equally valid as

  volatile int x;
  int a = x;
  int b = x;
  printf("%x %d\n", b, a);
, and neither needs to have the same output as your proposed fix.

C could've specified something like "arguments are evaluated left-to-right" or "if two arguments have the same expression, the expression is [only evaluated once]/[always evaluated twice]". But it didn't, so the developer is left gingerly navigating a minefield every time they use volatile.

Re: Everything in C is undefined behavior

#305
post #234

Earlier quoted context omitted.

Um, as an embedded developer, you don't develop the code to run on your machine, you develop it to run on the same target as you expect to deploy to, sitting on your desk next to you. I have lots of my code running day-in, day-out on literally hundreds of millions of machines. The approach to "getting it working" is exactly OP's. I'll admit to being pretty defensive and anal in checking values and return-codes (more…

Embedded developers often suffer under archaic toolchains. There's plenty of reasons for that, but one of them is UB: a newer version of the compiler can completely change an embedded program's behaviour.

Where I was it was quite the opposite. The bloody compiler guys kept on updating the compiler, and we were required to use the OS-delivered one. Since we were often using pre-release OS's, the toolchain could change every week.

It did make you write robust and defensive code, though...

Re: Everything in C is undefined behavior

#306
post #299

Earlier quoted context omitted.

Author here. > It barely scratches the surface. I agree. The point of the post is not to enumerate and explain the implications of all 283 uses of the word "undefined" in the standard. Nor enumerate all the things that are undefined by omission. 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. And if it's not succeeded for 54 years, "try hard…

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?

Re: Everything in C is undefined behavior

#307
post #296

Earlier quoted context omitted.

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…

"volatile" tells the compiler it is _not_ safe to optimise away any read or write, so it can't just optimise that section away at all. > An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2…

Sure it can. That code path has unconditional UB and thus it is not valid.

Re: Everything in C is undefined behavior

#308
post #303

Earlier quoted context omitted.

Not sure why you're being downvoted. That's completely right. The example is silly. The code is obviously bad, doesn't matter if it's UB or not. I'm also not convinced (yet) that the example really is UB: I agree reading a volatile is "a side effect" in some sense, and GP cited a paragraph that says just that. But GP doesn't clearly quote that it's a side effect on the object (or how a side effect on an object is def…

The problem is that the function call as a whole is UB. Having the original example compile to the equivalent of volatile int x; int a = x; int b = x; printf("%x %d\n", a, b); is equally valid as volatile int x; int a = x; int b = x; printf("%x %d\n", b, a); , and neither needs to have the same output as your proposed fix. C could've specified something like "arguments are evaluated left-to-right" or "if two argument…

Not only is "arguments are evaluated left-to-right" less easy to formalize than you think, it would also make all C code run slower, because the compiler would no longer be able to interleave computations for more efficient pipelining. The same goes for "expression is [only evaluated once]/[always evaluated twice]".

Of course the developer is navigating a minefield every time they use volatile, that's why it's called "volatile" - an English word otherwise only commonly used in chemistry, where it means "stuff that wants to go boom".

Re: Everything in C is undefined behavior

#309
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…

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

Re: Everything in C is undefined behavior

#310

Earlier quoted context omitted.

My go-to example of "UB is everywhere" is this one: int increment(int x) { return x + 1; } Which is UB for certain values of x.

C23 removed the whole stuff about indeterminate value and trap representation. Underflow/overflow being silent or not is implementation defined.

Signed overflow is just undefined.
Post reply on HN