-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC changing the overflow behavior for usize in release builds to panic #2635
Conversation
I suspect this change is not feasible without also providing some way to opt-out of these runtime checks, even in release mode. An obvious option is to add a set of |
What makes you say it's not feasible, performance or some other concern? How would the behavior of |
Yeah, performance. My understanding is that enforcing any specific overflow semantics has a measurable cost on some platforms, even if it's zero-cost on other platforms, because different hardware has different "default" overflow behavior. Rust is less weird than C because it requires two's complement, |
I think this RFC fundamentally needs actual benchmark results (ideally a large variety of them), to allow everyone to have an informed discussion about costs versus benefits. |
I like this RFC, and I believe that is the direction we want to move in, ideally. A few things:
Furthermore, I agree with @comex; RFC 560 mentions performance a number of times as the reason to make the decisions we made for the current behavior; if the performance were acceptable, I think there'd be broad support for checking in every case, let alone for just these sizes.
Yes, this is true, but we decided that we don't care as much about supporting that hardware as we do having consistent semantics. Non-two's compliment hardware is mostly legacy that we don't support particularly well in the first place, see discussions like https://gankro.github.io/blah/rust-layouts-and-abis/
As the note says, it's not normative, but I think, in this moment, it's roughly true. |
I agree that measurements will ultimately be a necessity to accepting/merging this idea. In writing the RFC first, I wanted to address the chicken/egg scenario of writing the code before it was clear the idea was acceptable -- truth be told I expected people to find the idea of special casing There probably is performance differences on different architectures beyond the concern for those which don't have 2s complement arithmetic. x86 and ARM both have dedicated instructions for jump-on-overflow, however PPC and MIPS do not, so there's a non-trivial difference on the amount of code generated on these platforms for overflow checks. That's an excellent point about the current behavior being keyed on |
I think this is a great proposal and I'd love to see it adopted by Rust. Having an additional security layer is a huge advantage, and as noted in the description, it would have prevented exploitation of a number of past security issues. Currently it's possible to enable overflow checks for all integer types using something like
in the Perhaps a good way to move forward on this would be to add a (possibly unstable) mechanism, like This mechanism might be useful independently of whether the behaviour proposed in the RFC is adopted; for instance, I would choose to use it in my projects. |
If you want to introduce this I'd like it with an optimization pass as done by the Swift compiler. |
@leonardo-m Can you explain what you mean by that? I don't see overflow-checking as being something that'd be implemented as a compiler optimization. Generally the compiler optimization piece of this is removing overflow checks where there are range bounds on the inputs. |
I meant adding this to Rust: |
Yes, as I mentioned in the Future Plans section, I suspect this work will spur desires for new and improved optimizations, either in Rust or LLVM. It is my hope that such optimizations will be nice to haves and not hard requirements for this to be practical. There seems to be a lot of interest (unsurprisingly) in quantifying this. I'll take on trying to put together a proof of concept of this for Rustc that's good enough to get some measurements. |
on `usize` values: `usize` is consistently used in `core`/`std` APIs which deal | ||
in lengths, buffer sizes, etc., the kind of values where overflow can be | ||
dangerous, so it's no coincidence that historic integer-overflow vulnerabilities | ||
occured with `usize` values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a small thing, I think this should also happen for isize
-- code that's using offset
might be calculating in that type instead, and just generally I'd like the two types to be as similar as possible.
I really like the nuance in doing this just for the types that are most likely the problem. And the scariest perf problem would be something like That said, LLVM still can't fold sequential As an upper-bound perf experiment, consider just changing the default in release to be panic, and we can run a |
There was never such a bug in ring and the necessary checks are done there, so I don't think it makes sense to mention it here. ( |
According to the bug report "This didn't end up being an actual issue as it was covered by an early bounds check." I didn't check the other two examples cited as motivation. Also, I am mostly supportive of this proposal. However, I think the citations suggesting non-vulnerabilities are vulnerabilities should be removed. |
In Ring's case, that's why I described it as a "near miss" -- since it was unreachable, but the check wasn't near the overflow, and there was no type or other structure for ensuring the invariant. It was included because it demonstrated the potential pattern of overflow on In CrosVM's case, the overflow was probably unexploitable (at least, none of us figured out a way to), because of the size of the input data was bounded, not because there was any checking on the actual result of the arithmetic. This one definitely makes sense to include, in my view. |
I think in both cases, the code that prevents the overflow is far away from the code that it is protecting, and minimizing that distance is generally good. I don't know all the details regarding the CrosVM case. In the case of ring, at least, it's not accidental that overflow is avoided. Bounding the input size very early to prevent integer overflows later is a pretty common practice. For example, this is one reason why Anyway, again, I'm not trying to argue against this RFC; just I think the way ring is referenced is very misleading. |
As the one who found the first one, it's definitely exactly this, and was fixed by making the overflow panic: https://github.com/rust-lang/rust/pull/54399/files#diff-773807740b9d7f176c85b4e2e34b2607R434 |
There is a proposal floating around in C++ space to declare that Signed Integers are Two’s Complement. In that proposal, there is a survey of signed integer representations which concludes that there are no current non-two's-complement hardware architectures. The closest thing is some Unisys product line which has an ASIC to support code written for its '60s mainframes, which were ones' complement (and had 36 bit words!). So, i would suggest that it's safe to not consider non-two's complement machines at all. |
We discussed this briefly in the lang team meeting, and generally agreed with the thread on the following:
|
According to the previous RFC and policies, this is a backwards compatible
change.
Of course, we've always tried to do better than simply the letter of the
law, but we'd have to demonstrate real-world breakage.
…On Mon, Feb 18, 2019 at 2:19 PM vorner ***@***.***> wrote:
I do find usize acting differently than eg. u8 a bit weird and usually I
really dislike inconsistencies. But that being said, I think this instance
of weirdness is quite OK ‒ rust's stance to overflowing is mostly „don't do
it, but I might not check every time you don't, it's up to you“. So
tweaking the rules when this „might not check“ happens sounds good to me,
especially if it tends to prevent bugs.
But I'd like to raise a concern that I haven't seen here. Is this
backwards compatible change? Not everyone necessarily shares my
understanding of „please don't overflow“ and might have decided to a) turn
off the checks in Cargo.toml, b) rely on the overflow not panicking. By
upgrading the compiler to never version, wouldn't such code stop working?
Or is the general stance that every overflow is actually a bug therefore
that code should have never worked in the first place?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2635 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AABsiiRK5WrKFQ7odoHOxsbBQ7cbjk18ks5vOwrGgaJpZM4azQVI>
.
|
Perhaps an unresolved question could be added to request a crater run? |
This is a prototype for rust-lang/rfcs#2635 to enable us to collect some measurements.
[WIP] Make usize overflow always have debug-assertions semantics This is a prototype for rust-lang/rfcs#2635 to enable us to collect some measurements.
Team member @scottmcm has proposed to postpone this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
While I like this conceptually, it seems like current measurements of experimenting with this are showing about a 2-6% impact to the speed of the compiler. As such, I propose that we postpone considering changing the release default for now, pending further work. @rfcbot fcp postpone Process notes: I'm only proposing postponing the T-lang change here. I (personally) would absolutely like to see work here continue, as better optimizations around checked math will help even if we never change a default here (for example, in |
First missed optimization I've found: rust-lang/rust#58692 |
Ok, tracking down optimizations and getting fixes upstreamed into LLVM is a slower process than I'd hoped. In order to keep some momentum here, I'd like to propose a flag for rustc that implements the behavior described here; of doing panic for usize arithmetic but leaving other types alone. Does this require a full of RFC, or can it simply be pull requests to rustc? |
@alex AFAIK the compiler team decides what flags the compiler has, and an unstable flag is plausibly something that would be accepted, assuming the code maintenance cost is low. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Would it make sense to only add checks to either functions or modules that contain unsafe code? The heuristic here would be that bounds checks either happen in the unsafe code itself, the surrounding function or its sibling functions that encapsulate it into a safe interface? |
functions is definitely overly granular, you can fairly straightforwardly
have an integer overflow where the actual corruption happens in an unsafe
block elsewhere. The problem I see with schemes like these is that they
make it too difficult to reason about the level of protection you're
getting.
…On Thu, Apr 25, 2019 at 6:01 PM the8472 ***@***.***> wrote:
Would it make sense to only add checks to either functions or modules that
contain unsafe code? The heuristic here would be that bounds checks either
happen in the unsafe code itself, the surrounding function or its sibling
functions that encapsulate it into a safe interface?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2635 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAAGBEMZEHL2VG7PMKSJOTPSIS2NANCNFSM4GWNAVEA>
.
--
All that is necessary for evil to succeed is for good people to do nothing.
|
Well, if your module publishes a function, even if it is just |
Could some of the performance anxiety be mitigated by using |
Co-Authored-By: alex <alex.gaynor@gmail.com>
The final comment period, with a disposition to postpone, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC is now postponed. |
I have not forgotten about this, and continue to (as time allows) work on the missed-optimizations problem: rust-lang/rust#72549 is the current known blocker. rust-lang/rust#72237 was brought to my attention as an example of another bug that would have been caught by this RFC. |
Rendered