Hacker News new | ask | show | jobs
by mehrdadn 2230 days ago
How sure are you that that getting an unexpected numerical result isn't going to let an attacker take over your machine? In most code I see the behavior is just undefined and not paid attention to by the programmer, regardless of what the compiler is doing. A huge fraction of the time you'll just step out of the bounds of an array, just deterministically instead of nondeterministically. People don't pay attention to what happens in that case regardless except in like 0.01% of the time when they're writing some kind of bit manipulation magic, and in those rare cases they can handle them in C++ too, with a custom wrapper or an unsigned type or something.
1 comments

> A huge fraction of the time you'll just step out of the bounds of an array, just deterministically instead of nondeterministically.

Well arrays are bounds checked by default in Rust, so you can't do that one. You're more likely to hit a crash, which I think is decidedly better than the compiler deciding to optimise out or rewrite your function because it contained UB.

> Well arrays are bounds checked by default in Rust, so you can't do that one.

But that's my entire point. If you're observing a benefit here, it's decidedly not due to the wrap-around, but due to other features (like bounds checking), and the argument should be that those features make Rust better than C++. It seems strange to give praise to the multiplication wrap-around instead.

I think I get what you're saying. The practical benefit of defining signed integer overflow in C, without any other changes, might not be very big for most C programs, since they're likely to get an out-of-bounds access either way. I'd add to that that undefined signed overflow makes it much harder to write good C code. Even if you carefully check all your array bounds, an unexpected integer promotion somewhere in there might lead the optimizer to delete the check you wrote.
C is a strawman though when we're discussing C++. Checking array bounds in C (or I'd argue, pretty much checking anything in C) is just a losing battle. The lack of proper abstraction facilities perpetually fights against you. C++ actually lets you abstract checks away into the definitions so that you don't have to modify every usage site.

Regarding optimizers deleting your checks though: is that something you encounter in practice, or just something you see people ranting about in blog posts? Can you even trigger this behavior if you try? Have you seen it happen more than once in a blue moon? I know on my end it's either never happened to me (likely) or it's been long enough ago that I have no memory of it. Even when I actively go out of my way to make this kind of thing happen, it gives me a hard time. Even the most blatant examples you'd try don't end up getting optimized out like this. Try [1] for example. It's both out of bounds and an uninitialized read, and yet the check is still there. If anything it's incredibly disappointing how bad optimizers are at optimizing out bounds checks!

[1] https://gcc.godbolt.org/z/i-FMV-