Live data from Hacker News

Undefined behavior in C is a reading error

yodaiken.com

381–390 of 503 posts

Re: Undefined behavior in C is a reading error

#381
post #358

Earlier quoted context omitted.

> To do UB "optimizations", the compiler first needs to figure out that there is an UB it can "optimize" anyway. That's not how compwillrs work. In fact in the general case it is impossible to figure out at compile time that "there is an UB". The compiler instead assumes as an axiom that no UB can ever happen and uses the axioms to prove properties of the code. These days if you want to catch UB, compile with -fsanit…

> These days if you want to catch UB, compile with -fsanitize=undefined-behaviour. The program wll then trap if UB is actually detected at runtime. So, let me get this straight, someone wants to make sure pointer p is not null (in the wrong way), and codes something like the examples in posts above like if (!p) ... and if that doesn't trigger calls use(*p), but compiler decides p can never be null because that would…

It is a bit different.

Ubsan will abort an invalid program if it detect ub. It doesn't let you handle it. So you shouldn't remove the erroneous check, but fix it so it is no longer erroneous, and ubsan will help you identify these errors.

Also ubsan adds significant overhead so it is not really appropriate for production builds unfortunately (hence my wish for a less powerful ubsan-lite but with lower overhead).

Re: Undefined behavior in C is a reading error

#382

Earlier quoted context omitted.

Note that (void *)0 is always NULL, as mandated by the standard. But, to address the content of your comment: defined behavior at runtime is not necessarily good behavior at runtime. Defining signed integer overflow to wrap, for example, is probably a bad idea, because this is rarely the intent of the code. Having all such operations trap might be a good idea, but now you're going to get the same "stop breaking my wo…

Yes, thankfully at least with NULL they didn't fall into the legacy trap and messed up the standard with non-zero NULL that some machines before have been kind of using. >Defining signed integer overflow to wrap, for example, is probably a bad idea I wouldn't call it great behavior, but it's at least what most people expect will happen, and most people will be able to understand what's going on, and it's fast on most…

I would say that most people expect it not to happen. If they really had to mandate a behavior, it should be to trap.

Re: Undefined behavior in C is a reading error

#383
post #287

Earlier quoted context omitted.

For me, the canonical UB example is a buffer overflow. No matter how you define UB, in practice a buffer overflow can result in for example, a system crash or - given appropriate very specific input data - encrypting all the files on your hard drive for a ransom. Requiring compilers to restrict UB to something similar to unspecified behavior (where the behavior is not specified by the standard, but a C implementation…

It goes further than that. The debates around UB a more about whether the compiler can assume that there are no buffer overflows and perform optimizations based on that. For example, if you have a local variable `char buffer[16]`, and there is an access `buffer[i]`, should the compiler be allowed to derive that 0 = 16, why shouldn't it? But some argue that the compiler shouldn't, exactly because such automated formal…

What I never see mentioned in this type of discussion is what this compiler trick buys us. Like how much faster does my program run because of deductions like these? And are there any patterns that particularly benefit from it? Could they hint the constraint manually?

Re: Undefined behavior in C is a reading error

#384
post #354

Earlier quoted context omitted.

Explicit bounds everywhere mean that those bounds need to be automatically checked every time instead of only where explicitly specified by the programmer. This leads to safer code at a nontrivial performance tradeoff, one which would not be acceptable for C.

You could imagine bounds being baked into the types and checked at compile time. int{0..10} foo = 4 int{0..10} bar = 5 int{0..10} buzz = foo+bar // ERR: 10+10 potentially > 10 int{0..10} boom = wrapping_add(foo, bar) // OK int{0..100} sum = foo+bar // OK There are tools which can do this, for example Code Contracts in C#. It becomes rather tedious and verbose so is something usually only left for very safety critical…

This could be useful in C for some situations. That said, the above is completely useless if just only one of those values (ranges or assignments) is dynamic: you'll be back to carefully (and manually) checking you don't overflow.*

*edit: unless your compiler automatically emits instructions to do the check at runtime; a thing that won't happen (and I don't want) in C.

Re: Undefined behavior in C is a reading error

#385

Commenters here seem to be missing the core thesis of this article. It's not about what the standard literally means; it's about it's spirit -- and the reason for its spirit. The issue is "undefined behaviour" should never have been interpreted this extremely. The standard may be silent on how extreme, but it is implausible to suggest that the standard was actually written to enable this. Compiler writers for C! dism…

The spirit of the article and your comment seems to underrate the efforts required to come up with something like the standard for a C compiler.

It's not a "perverse shield". In C, "optimize for correctness" is the programmer's job. I don't want to sound dismissive, and I don't pretend you to write a compiler, but please tell me how would you word a global standard for generating compilers that can compile for hundreds of architectures, with the main focus of being portable and generating the most performant code (no runtime checks).

You might come up with a standard similar to something like Rust (which does not have an standard yet, and has only a single compiler "brand"). But Rust is super-difficult to understand and part of its safeness depends on runtime checks, including runtime checks on ownership like RefCell, impacting on performance. The same goes for Ada and other runtime-checked languages.

Or you'll end up with something like a standard for C, in which you assume the programmer can be somewhat trusted allowing the compiler to generate faster code, and having to deal with little caveats that depends on certain architectures.

Re: Undefined behavior in C is a reading error

#386
post #197
post #59

Earlier quoted context omitted.

> Vanilla C no longer gives them the tools to do that on a modern processor Can you elaborate on this point?

C was created during a time where instructions were executed linearly with no vectorization, memory was a flat space with no CPU caches, and there wasn’t a branch predictor that may or may not execute the correct program branch in advance. The list goes on but the rest is beyond my scope. C was designed for a now obsolete computer architecture model and over the years this old model has essentially become an abstract…

> now obsolete computer architecture model

I think this is kind-of dismissive. You seem to assume that everyone is programming modern x86 machines. What about embedded? My little PIC32/STM32/ATMEGA do not have caches or predictors, and has a flat memory space.

Thank god there is the C standard, that even today after more than 30 years, give compilers a clear set of rules allowing them to emit code for those thousands of architectures used today in the dozens of embedded devices we have in our houses/offices/industries today, and not only that, it allows to squeeze the maximum performance out of these microcontrollers, for a language that is not plain assembler.

Re: Undefined behavior in C is a reading error

#387

Most of this discussion revolves around integer overflow. Part of the problem is that most of the computer hardware is now twos-complement arithmetic. Programmers think of that as part of the language. It's not, for C. C has run, in the past, on - 36 bit ones complement machines (DEC and UNIVAC) - Machines with 7-bit "char" (DEC) - Machines with 9-bit "char" (UNIVAC, DEC) - Machines where integer overflow yields a pr…

I've heard of wrap around and saturate, but promote to float? What?! Do you have more info on how that worked?

Same way it does in Javascript?

Re: Undefined behavior in C is a reading error

#388
post #383
post #287

Earlier quoted context omitted.

It goes further than that. The debates around UB a more about whether the compiler can assume that there are no buffer overflows and perform optimizations based on that. For example, if you have a local variable `char buffer[16]`, and there is an access `buffer[i]`, should the compiler be allowed to derive that 0 = 16, why shouldn't it? But some argue that the compiler shouldn't, exactly because such automated formal…

What I never see mentioned in this type of discussion is what this compiler trick buys us. Like how much faster does my program run because of deductions like these? And are there any patterns that particularly benefit from it? Could they hint the constraint manually?

There are plenty of examples in this thread alone.

In my opinion hinting won't help. Everyone who cares about the performance gain will enable the hint (which I expect will be almost everyone) so you have won nothing but added noise with the hint.

Re: Undefined behavior in C is a reading error

#389
post #369

Earlier quoted context omitted.

We had sanitizers since C exists, 1979 to be more exact. "Although the first edition of K&R described most of the rules that brought C's type structure to its present form, many programs written in the older, more relaxed style persisted, and so did compilers that tolerated it. To encourage people to pay more attention to the official language rules, to detect legal but suspicious constructions, and to help find inte…

I was going to add "in open source compilers" to hedge my statement :). That seems to be a static analysis tool though (which generally have not been great). Did it also inject runtime checks?

[deleted]

Re: Undefined behavior in C is a reading error

#390
post #369

Earlier quoted context omitted.

We had sanitizers since C exists, 1979 to be more exact. "Although the first edition of K&R described most of the rules that brought C's type structure to its present form, many programs written in the older, more relaxed style persisted, and so did compilers that tolerated it. To encourage people to pay more attention to the official language rules, to detect legal but suspicious constructions, and to help find inte…

I was going to add "in open source compilers" to hedge my statement :). That seems to be a static analysis tool though (which generally have not been great). Did it also inject runtime checks?

No, but still not even that gets the love it deserve.

And a famous commercial variant of it has been PC-lint from https://www.gimpel.com/.

Being available on open source compilers does little to change the culture, as per latest surveys only 11% of developers care to use any kind of tooling for improving their code quality in C and C++.

At CppCon a couple of years ago, only about 1% of the audience answered positively to Herb Sutters' question.

Post reply on HN