[rust-dev] Integer overflow, round -2147483648

Gábor Lehel glaebhoerl at gmail.com
Sun Jun 22 06:31:41 PDT 2014


On Sat, Jun 21, 2014 at 11:21 PM, Vadim Chugunov <vadimcn at gmail.com> 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
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140622/0e847c13/attachment.html>


More information about the Rust-dev mailing list