Skip to content

Flags for unspecified behaviour #423

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

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions text/0000-unspecified-flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
- Start Date: 2014-10-28
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

Allow control of unspecified behaviour via compiler flags

# Motivation

Several things in Rust shouldn't have a well-defined result. However,
safety and debugging, would like some well-defined option.

# Detailed design

There are several things in Rust that don't have a well-specified behaviour.
Among them are:

* Signed Integer arithmetic overflow
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually well-specified as wrapping around: http://doc.rust-lang.org/reference.html#behaviour-not-considered-unsafe
I suppose this prevents x + 1 > x and (2*x) / 2 from being optimized to true and x respectively, and it might be interesting to investigate if such optimizations would really make existing Rust code faster. But for now it is well-specified.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that even if it wasn't mentioned in the reference, it would still be well-defined. The reference is not a language specification and does not cover most of Rust's semantics. A flaw in the reference does not change the definition of the language. The implementation is the closest thing to a specification right now.

It would be backwards incompatible to alter a guarantee that the compiler provides, even if it is not written down anywhere. Fixing undefined behaviour (not the same as unspecified behaviour) is not backwards incompatible. Any UB is an implementation soundness bug..

* Shift amount overflow
* Checked Array OOB indexing

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out-of-bounds indexing is currently well-defined as failing.

* Divide-by-Zero

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Division by zero is currently well-defined as failing.

* LLVM UB in unsafe intrinsics

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a difference between undefined behaviour and something that's left unspecified. It is explicitly specified as being undefined behaviour. That means a program doing it is memory unsafe / incorrect and the language does not provide any guarantees about what will happen.

* Unchecked Array OOB indexing (if we take #392 or some variant)

In these cases, there are several things we could want to do – the primary
options are task failure^H^H^H^H^H^H^Hpanic, aborting, undefined behaviour
(which is unsafe except in the first 4 cases), and (in the former 2)
returning a not-entirely-correct result (actually, with shift overflow,
there are *2* such results – either x86-style masking of the shift count,
or "correctly" returning 0/-1).

Add a compiler flag that controls the choice, -S TYPE=ACTION

Where TYPE is one of `signed_overflow`, `shift_overflow`,
`checked_oob`, `divide_by_zero`, `unsafe_intrinsic`, `unsafe_oob` (and
maybe more), and ACTION is one of "default", "fail", "undefined",
or (with the first 2 options) "wraparound". Add "all" and "unsafe_all" flags
to control the defaults (note that actually it is the safe options that
allow unsafety in safe code, which can be confusing). Have the default
be the current choice (currently we have `signed_overflow=wrap`,
`shift_overflow=undefined`, `checked_oob=fail`, `divide_by_zero=fail`,
`unsafe_intrinsic=undefined` and probably `unsafe_oob=undefined`) unless
we make some different decision.

For example, if we're debugging and want fail-fast, we could have
`-S all=fail`, and until we do something with shift amounts people could want
`-S shift_overflow=wrap`.

# Drawbacks

This would tempt people could use `-S checked_oob=undefined` and get 0wned.

# Alternatives

Also allow this on attributes. This would make it more likely to be
mis-used.

# Unresolved questions

None currently.