On Sat, Jun 21, 2014 at 11:21 PM, Vadim Chugunov <[email protected]> wrote:
> My 2c: > > The world is finally becoming security-conscious, so I think it is a only > matter of time before architectures that implement zero-cost integer > overflow checking appear. I think we should be ready for it when this > happens. So I would propose the following practical solution (I think > Gabor is also leaning in favor of something like this): > > 1. Declare that regular int types (i8, u8, i32, u32, ...) are > non-wrapping. > Check them for overflow in debug builds, maybe even in optimized builds on > platforms where the overhead is not too egregious. There should probably > be a per-module performance escape hatch that disables overflow checks in > optimized builds on all platforms. On zero-cost overflow checking > platforms, the checks would of course always be on. > Also, since we are saving LLVM IR in rlibs for LTO, it may even be > possible to make this a global (i.e. not just for the current crate) > compile-time decision. > > 2. Introduce new wrapping counterparts of the above for cases when > wrapping is actually desired. > > If we don't do this now, it will be much more painful later, when large > body of Rust code will have been written that does not make the distinction > between wrapping and non-wrapping ints. > The prospect of future architectures with cheaper (free) overflow checking isn't my primary motivation, though if we also end up better prepared for them as a side effect, that's icing on the cake. My primary motivation is that, outside of a couple of specialized cases like hashing and checksums, wraparound semantics on overflow is **wrong**. It may be well-defined behavior, and it may be fast, but it's **wrong**. What's the value of a well-defined, performant semantics which does the wrong thing? I also agree that performance is non-negotiable in this case, however. The only good thing about always wrong is that it's not that hard to do better. Given the circumstances, I think the least bad outcome we could achieve, and which we *should* aim to achieve, would be this: * Where performance is known to not be a requirement, Rust code in the wild uses either overflow-checked arithmetic or unbounded integer types, with the choice between them depending on ergonomic and semantic considerations. * When the performance requirement can't be ruled out, Rust code in the wild uses arithmetic for which overflow checking can be turned on or off with a compiler flag. For testing and debugging, it is turned on. For production and benchmarks, it is turned off. * For code where wraparound semantics is desired, the appropriate facilities are also available. Given the discussion so far, the design I'd be leaning toward to accomplish the above might be something like this: * Two sets of fixed-sized integer types are available in the `prelude`. * `u8`..`u64`, `i8`..`i64`, `int`, and `uint` have unspecified results on overflow (**not** undefined behavior). A compiler flag turns overflow checks on or off. Essentially, the checks are `debug_assert`s, though whether they should be controlled by the same flag is open to debate. * `uc8`..`uc64`, `ic8`..`ic64`, `intc`, and `uintc` are *always* checked for overflow, regardless of flags. (Names are of course open to bikeshedding.) * Given that these are not really different semantically, automatic coercions between corresponding types can be considered. (Even then, for `a + b` where `a: int` and `b: intc`, explicit disambiguation would presumably still be required.) * Unbounded integer types using owned memory allocation are available in the `prelude`. I might prefer to call them `Integer` and `Natural` instead of `BigInt` and `BigUint`. * Types and/or operations which wrap around on overflow are available in the standard library. Given how specialized the use cases for these seem to be, perhaps they could even go directly in the `hash` module. It's not clear to me yet whether a separate set of types (`uw8`..`uw64`, `iw8`..`iw64`) or just a separate set of operations on the `prelude` types (e.g. `trait WrappingAdd`) would be preferable. * Unbounded integer types which use garbage collected allocation are available in the `gc` module. > > Vadim > > > _______________________________________________ > Rust-dev mailing list > [email protected] > https://mail.mozilla.org/listinfo/rust-dev > >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
