Skip to content
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

Resolve overflow behavior for RangeFrom #72368

Merged
merged 1 commit into from
May 30, 2020
Merged

Conversation

CAD97
Copy link
Contributor

@CAD97 CAD97 commented May 20, 2020

This specifies a documented unspecified implementation detail of RangeFrom and makes it consistently implement the specified behavior.

Specifically, (u8::MAX).next() is defined to cause an overflow, and resolve that overflow in the same manner as the Step::forward implementation.

The inconsistency that has existed is <RangeFrom as Iterator>::nth. The existing behavior should be plain to see after #69659: the skipping part previously always panicked if it caused an overflow, but the final step (to set up the state for further iteration) has always been debug-checked.

The inconsistency, then, is that RangeFrom::nth does not implement the same behavior as the naive (and default) implementation of just calling next multiple times. This PR aligns RangeFrom::nth to have identical behavior to the naive implementation. It also lines up with the standard behavior of primitive math in Rust everywhere else in the language: debug checked overflow.

cc @Amanieu


Followup to #69659. Closes #25708 (by documenting the panic as intended).

The documentation wording is preliminary and can probably be improved.

This will probably need an FCP, as it changes observable stable behavior.

@rust-highfive
Copy link
Collaborator

r? @Mark-Simulacrum

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 20, 2020
@Mark-Simulacrum
Copy link
Member

r? @Amanieu

Copy link
Member

@Amanieu Amanieu left a comment

Choose a reason for hiding this comment

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

LGTM

@rfcbot fcp merge

src/libcore/ops/range.rs Outdated Show resolved Hide resolved
@Amanieu Amanieu added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label May 20, 2020
@Amanieu
Copy link
Member

Amanieu commented May 20, 2020

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented May 20, 2020

Team member @Amanieu has proposed to merge 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.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels May 20, 2020
@SimonSapin
Copy link
Contributor

It also lines up with the standard behavior of primitive math in Rust everywhere else in the language: debug checked overflow.

In most crates, rustc decides at compile-time whether to emit code for overflow checks based on configuration. The standard library however is distributed pre-compiled. I vaguely recall there is some mechanism to make standard library functions/methods run overflow checks based on whether the caller is in a crate that wants them. However I don’t remember any more than that, including how it’s called so I could grep for it.

How does this work? Does this require annotation to be added to impls of Iterator::nth, Step::forward and every other function that ends up on the call stack?

@Mark-Simulacrum
Copy link
Member

It's the rustc_inherit_overflow_checks attribute. I believe it works on traits too. I think it only needs to be added to the function containing the + operator (or whatever math is being done).

@SimonSapin
Copy link
Contributor

I believe it works on traits too.

You mean on trait impls, right? Like here:

impl Add for $t {
type Output = $t;
#[inline]
#[rustc_inherit_overflow_checks]
fn add(self, other: $t) -> $t { self + other }
}

I think it only needs to be added to the function containing the + operator (or whatever math is being done).

@CAD97 Is that why src/libcore/iter/range.rs has calls to Add::add and Sub::sub in a couple places instead of using + and -? To try and take advantage of the rustc_inherit_overflow_checks attributes there?


// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on
// the settings for the crate they are codegened in.
let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);

Per that comment, rustc_inherit_overflow_checks only works for generic code with a type parameter chosen by users of the standard library, so that code is translated when compiling these users rather than when pre-compiling the standard library. Is that correct?

src/libcore/iter/range.rs has macro-generated concrete impls such as impl Step for u32. Does not work there rustc_inherit_overflow_checks? Or does it rely on #[inline] attributes to only be translated downstream?

@Mark-Simulacrum
Copy link
Member

I believe if something is marked as #[inline] it should work, but we'll probably want to check and document this somewhere -- maybe on the libs team page on forge (https://forge.rust-lang.org/libs/maintaining-std.html).

@SimonSapin
Copy link
Contributor

My understanding of #[inline] is that it’s a hint that may or may not be observed by LLVM. Relying on it for documented semantics seems fragile.

@Mark-Simulacrum
Copy link
Member

We don't need the function to be inlined by LLVM -- we just need the codegen to happen in leaf crates. Currently, that's the behavior that inline forces, so in that respect it should be fine. We rely on this for pretty much all of the "maybe checked" arithmetic exposed by libcore/std I think

@CAD97
Copy link
Contributor Author

CAD97 commented May 20, 2020

@SimonSapin

Is that why src/libcore/iter/range.rs has calls to Add::add and Sub::sub in a couple places instead of using + and -? To try and take advantage of the rustc_inherit_overflow_checks attributes there?

Yes, and this is the way that it was handled before the Step redesign touched everything in that file. Step::add_one was just #[inline] { Add::add(self, 1) }. Honestly, I'm not exactly certain how exactly inherited overflow checks work, I just know that they do.

@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label May 20, 2020
@rfcbot
Copy link

rfcbot commented May 20, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label May 20, 2020
@SimonSapin
Copy link
Contributor

Sounds good, thanks all.

@Elinvynia Elinvynia removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 27, 2020
@dtolnay
Copy link
Member

dtolnay commented May 28, 2020

@bors r+

@bors
Copy link
Contributor

bors commented May 28, 2020

📌 Commit 406852a has been approved by dtolnay

@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label May 28, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request May 29, 2020
Resolve overflow behavior for RangeFrom

This specifies a documented unspecified implementation detail of `RangeFrom` and makes it consistently implement the specified behavior.

Specifically, `(u8::MAX).next()` is defined to cause an overflow, and resolve that overflow in the same manner as the `Step::forward` implementation.

The inconsistency that has existed is `<RangeFrom as Iterator>::nth`. The existing behavior should be plain to see after rust-lang#69659: the skipping part previously always panicked if it caused an overflow, but the final step (to set up the state for further iteration) has always been debug-checked.

The inconsistency, then, is that `RangeFrom::nth` does not implement the same behavior as the naive (and default) implementation of just calling `next` multiple times. This PR aligns `RangeFrom::nth` to have identical behavior to the naive implementation. It also lines up with the standard behavior of primitive math in Rust everywhere else in the language: debug checked overflow.

cc @Amanieu

---

Followup to rust-lang#69659. Closes rust-lang#25708 (by documenting the panic as intended).

The documentation wording is preliminary and can probably be improved.

This will probably need an FCP, as it changes observable stable behavior.
@RalfJung
Copy link
Member

@bors rollup

bors added a commit to rust-lang-ci/rust that referenced this pull request May 30, 2020
Rollup of 9 pull requests

Successful merges:

 - rust-lang#72299 (more `LocalDefId`s)
 - rust-lang#72368 (Resolve overflow behavior for RangeFrom)
 - rust-lang#72441 (Fix ICE with explicit late-bound lifetimes)
 - rust-lang#72499 (Override Box::<[T]>::clone_from)
 - rust-lang#72521 (Properly handle InlineAsmOperand::SymFn when collecting monomorphized items)
 - rust-lang#72540 (mir: adjust conditional in recursion limit check)
 - rust-lang#72563 (multiple Return terminators are possible)
 - rust-lang#72585 (Only capture tokens for items with outer attributes)
 - rust-lang#72607 (Eagerly lower asm sub-expressions to HIR even if there is an error)

Failed merges:

r? @ghost
@bors bors merged commit 93d45a0 into rust-lang:master May 30, 2020
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels May 30, 2020
@CAD97 CAD97 deleted the rangeto branch November 6, 2023 19:50
@dtolnay dtolnay self-assigned this Mar 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Integer overflow false positive with (0u8..).take(256)
10 participants