Live data from Hacker News

Catch-23: The New C Standard Sets the World on Fire

queue.acm.org

141–150 of 275 posts

Re: Catch-23: The New C Standard Sets the World on Fire

#142

Earlier quoted context omitted.

It is just the opposite. UB is a clarification to tell programmers what the language considers to be undesired behavior. If they didn't say anything, it would be always a mystery if a certain construct was allowed or not, effectively making it compiler dependent. Compilers would also have less avenue for creating optimizations. In the next iterations of the C standard we may see more constructs classified as UB.

Is the improved performance of C over say Java, or Rust (which both have much less undefined behaviour -- Java almost none) worth the pain and bugs which have been caused by UB? Honestly, I don't think so, and as computers get more powerful and the amount of the world which relies on their correct functioning grows, I feel the arguments for UB become increasingly difficult to justify.

I went to look up undefined behaviour in Rust and I got this scary warning:

Warning: The following list is not exhaustive. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. The following list is just what we know for sure is undefined behavior. Please read the Rustonomicon before writing unsafe code.

After the warning was a list of many of the same types of things that are undefined behaviour in C. In addition, there’s a bunch more undefined behaviour related to improper usage of the unsafe keyword.

So I don’t think you get a free lunch with Rust here. What you get is a “safe” playground if you stay within the guard rails and avoid using the unsafe keyword. But then you are limited to writing programs which can be expressed in safe Rust, a proper subset of all programs you might want to write.

Furthermore, the lack of a formal specification for Rust is one area where it lags behind C, a standardized language. All of the undefined behaviour in C is decreed and documented by the standard, having been decided by the committee. Rust, on the other hand, may have weird and unpredictable behaviour that you just have to debug yourself, which may or may not be compiler bugs.

Re: Catch-23: The New C Standard Sets the World on Fire

#143
post #33

Earlier quoted context omitted.

You should consider a program with undefined behaviour to be the equivalent of a mathematical proof that contains an unstated contradiction. Ex falso quodlibet : from a falsehood anything follows. Also called the principle of explosion. Undefined behaviour renders your entire program meaningless. It must be avoided at all costs. Using undefined behaviour on purpose is like sticking a fork in an electrical socket.

That's not an argument to keep live grenades laying around, it's an argument to remove them from the spec. Like signed int being UB. Define it to have 2 complement semantics. Problem solved. I'm sure the nutters trying to extend C++ with templates will howl but this is C not C++. And seriously C++ is dead man walking at this point.

C23 does make two’s complement standard. It also adds checked arithmetic so you can safely avoid signed overflow.

It does not make signed overflow defined behaviour. This would prevent integer operation reordering as an optimization, leading to slower code.

Re: Catch-23: The New C Standard Sets the World on Fire

#144
post #5

Earlier quoted context omitted.

I agree that realloc was poorly defined for the 0 size case, I think UB or IDB both would have worked in this case to really drive that point home, the WG chose UB. That being said, you're completely wrong about what UB means. Making use of UB may as well initiate the rise of zombie velociraptors. Except for the situation where your implementation explicitly specifies that it provides a predictable behaviour for a sp…

> this kind of mislead assumption is one of the major sources of bugs in C code. This is not even close to be true. Most bugs in C code are from programmer mistakes, not from UB behavior. The exaggeration that is spread by some people regarding UB is close to absurd. If something is UB, it may generate different results in different situations, even with the same compiler. The standard is just clarifying this problem…

If I am not wrong, one major security bug that C programs usually face is buffer overflow, which is an undefined behavior.

Re: Catch-23: The New C Standard Sets the World on Fire

#145
post #79
post #51

Earlier quoted context omitted.

I think the point is that if the `argc always greater than 2, permitting the compiler to optimize the entire block to just: return printf("%s: we see %s", argv[0], argv[1]); IOW, the conditional has been elided. But you're right in that the wording of the complaint doesn't match the example. The author presumably had in mind some of the more infamous NULL pointer-related optimizations, without spending the time to pu…

I interpreted the author's characterization to be about something like: 1 if (argc in which not just lines 4-6,8 go away (as you said) but also lines 1-2. It makes sense to me but I can see why the author would characterize this situation as "license to use an unreachable annotation on one code path to justify removing an entirely different code path that is not marked unreachable" . In a different world one might ex…

On the other hand, that has been the behaviour of optimising compilers in the face of UBs for years at this point, decades maybe. The linux kernel was hit by a deref' constraint propagation back in 2009 or so.

This is a behaviour I would absolutely expect from the construct, I would even qualify it as "the point".

Re: Catch-23: The New C Standard Sets the World on Fire

#146

Earlier quoted context omitted.

This is not about code that's found to be unreachable through static analysis (where compilers might warn), but about a manual programmer annotation that claims the code is dynamically unreachable even though statically it might look otherwise.

Why would you want that? Is it to aid building for multiple targets? For debug builds?

> Why would you want that?

To aid with optimisation, it basically lets you ask the compiler to remove branches, and provide constraints to the same.

An implementation might trap in debug code, but given no context would be provided you'd likely avoid this and would instead use your own wrapper macro to output a message of some sort in that case.

Re: Catch-23: The New C Standard Sets the World on Fire

#147

Earlier quoted context omitted.

This is not about code that's found to be unreachable through static analysis (where compilers might warn), but about a manual programmer annotation that claims the code is dynamically unreachable even though statically it might look otherwise.

Why would you want that? Is it to aid building for multiple targets? For debug builds?

You can for example use it to give hints to the compiler that allows for optimisations, that it couldn't do otherwise.

Described e.g. here https://web.archive.org/web/20160508051118/http://blog.regeh...

Github https://github.com/preames/llvm-assume-hack

Re: Catch-23: The New C Standard Sets the World on Fire

#148

Earlier quoted context omitted.

That sounds good in theory, but many things that are UB in C/C++ are UB because they are really hard to verify at compile time which makes them almost impossible to program around. Any signed addition in C is potential UB unless you have a proof that all numbers that will ever be input to the addition won't cause overflow (which is made harder because C doesn't define the size of the default integer types). Furthermo…

> many things that are UB in C/C++ are UB because they are really hard to verify at compile time which makes them almost impossible to program around The second half of the sentence doesn't follow from the first. Take everyone's favorite example, signed integer overflow: all you have to do to avoid UB on signed integer overflow is check for overflow before doing the operation (and C23 finally adds features to do that…

My complaint here is that it took C more than 30 years between defining signed integer overflow as UB and providing programmers with standard library facilities to check if a signed integer operation would result in overflow.

I much prefer Rust's approach to arithmetic, where overflow with plain arithmetic operators is defined as a bug, and panics on debug-enabled builds, plus special operations in the standard library like wrapping_add and saturating_add for the special cases where overflow is expected.

Re: Catch-23: The New C Standard Sets the World on Fire

#149

Earlier quoted context omitted.

Why would you want that? Is it to aid building for multiple targets? For debug builds?

> Why would you want that? To aid with optimisation, it basically lets you ask the compiler to remove branches, and provide constraints to the same. An implementation might trap in debug code, but given no context would be provided you'd likely avoid this and would instead use your own wrapper macro to output a message of some sort in that case.

But this example isn't adding a constraint. The if statement is getting optimised away???

Re: Catch-23: The New C Standard Sets the World on Fire

#150
post #34

Earlier quoted context omitted.

> Finally, the checked arithmetic operations returning false on success is a horror show. This seems in line with C conventions? Generally a 0 return code means success.

With int statuses, not with bools. It’s just a twisted logic in return value you have to deal with in your head. “If checked operation has a status, then it failed.” - ok “If checked operation [is true], then it failed.” - wat

> With int statuses, not with bools

Which C historically did not have, so int played that role. The function is the same, and the existing idioms remain.

Post reply on HN