Hacker News new | past | comments | ask | show | jobs | submit login

If this kind of optimization is unacceptably risky for your use case, you need a different programming language, not a different C compiler.



"unacceptably risky" except I can't think of anything more basic than asking the computer if a > b and it fails at that?


UB invades your whole program, not specific lines.

However in this case, the culprit wasn't comparison `a > b`, but assignment `a = b`.

In general, addition like 'a + b' also isn't safe in C.


It's not the assignment. It's the multiplication x * 0x1ff.

The compiler has done range analysis and knows that at this point, x is non-negative. The programmer has dilgently ensured that values are such that the multiplication can't overflow, therefore the result of it is also non-negative. That means the later check for i being non-negative is trivially true.


If it's wrong break on compiler time, not on run time

The problem is the compiler going implementation defined on the multiplication/assignment then going all language lawyer on the following line and blaming the user

> In general, addition like 'a + b' also isn't safe in C.

Cool, another reason to retire it


> If it's wrong break on compiler time, not on run time

The number being multiplied isn't known until runtime, so there's not a good way of doing this.


Well, funny that the compiler sees no problem in removing a check (on compile time) of a value that is totally possible to obtain, on runtime


Isn’t the very base issue the program didn’t sanitize the input?

Just blindly accepting user input is universally bad methinks.


We might ask if gcc will feel like keeping the sanitizing checks or it will take them out due to some bout of language lawyering as well...


I'm not sure what you mean by 'keping the sanitizing check'?

A C program is basically a bunch of bytes, and the C standard tells you what those bytes are supposed to mean. A compiler's job is to translate the bytes into whatever target language you fancy, and making sure to preserve the proscribed behaviour. And that's exactly what the compiler did.


Why would “basic” and “correct” overlap in any way?


how does it fail at that? it does exactly what the standard advertises. you need to write standard-compliant code.


It would seem GCC is doing its very best to make C an irrelevant language. They're taking "-pedantic" a bit too seriously.


All optimizing compilers do stuff like this. You yourself ask the compiler to do it when you pass it '-O2'. Its default behavior is, in fact, to not optimize based on the assumption that UB won't happen.


No. Just compile with -fno-strict-overflow, like I do.


For signed overflow in particular, sure. I was talking more about these kind of optimizations for UB in general.


Do you have any specific languages in mind?


Author of linked article mentions Rust


Fun thing there is rust feeds into the same optimisation pipeline as C or C++, so there's a definite risk of it inheriting some of their semantics via errors in the compiler implementation.


There have been several cases where Rust's use of "restrict" pointers exposed bugs in LLVM, and the Rust compiler had to disable some optimizations as a workaround. But I haven't heard of anything like that happening with signed overflow. (Probably any bugs with basic integer behavior would get noticed quickly?)

Another thing to watch out for here (especially if anyone's trying to transpile Rust to C) might be C's strict aliasing rules accidentally getting applied to Rust raw pointers.


The promise of Rust is that you never run into undefined behavior if you only use safe code. There are some caveats (using dependencies with badly written unsafe code, the noalias bugs others mentioned) but in the general case, if you're writing code without 'unsafe' blocks, you're not going to trigger UB.

You're certainly not going to run into LLVM optimizing your bound-check out of existence because it occurs after an overflowing operation.


Compiler bugs are always a potential issue for fuckup.

Hell, rust has had codegen issues because it extensively leveraged features which are almost non-existent in C, and thus were little exercised and poorly tested.


Rust is a good replacement for most use cases, but I think specifically in case where you're looking for a more predictable and less risky implicit behavior, the replacement should be more stable and predictable than Rust is at the moment.


What kind of language is C replacement without UB and better concurrency and more stable/predictable than Rust?


Question, but where do you get the idea that Rust is not stable or predictable? I understand you were asking for something _more_ stable/predictable than Rust, but Rust is already very stable and very predictable (in fact I can't think of any ways that Rust is "unpredictable").


Basically anything else.


C has a specification and weird stuff doesn't happen as long as you follow it. Doing so is very hard at times, but if a project cares about unpredictable optimizations, then it probably also cares about other kinds of unpredictable behavior. Which unfortunately eliminates a lot of languages that make no guarantees about their semantics.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: