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

Integer overflow on String::drain() with an inclusive range #72237

Closed
bodil opened this issue May 15, 2020 · 11 comments
Closed

Integer overflow on String::drain() with an inclusive range #72237

bodil opened this issue May 15, 2020 · 11 comments
Labels
C-bug Category: This is a bug. P-high High priority T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@bodil
Copy link

bodil commented May 15, 2020

I would expect this code to panic at the drain() because usize::max_value() is an out of bounds index:

fn string_drain_overflow() {
    let mut string = String::new();
    string.drain(..=usize::max_value());
}

Instead, it succeeds and returns an empty iterator. Looking at the implementation for String::drain(), I'm assuming an integer overflow happens at line 1542 Included(&n) => n + 1 and the range is taken to be 0..0. Honestly, I expected the add operation itself to panic on overflow so I'm not entirely sure what the correct behaviour is here.

Meta

rustc 1.43.1 (8d69840ab 2020-05-04)
binary: rustc
commit-hash: 8d69840ab92ea7f4d323420088dd8c9775f180cd
commit-date: 2020-05-04
host: x86_64-unknown-linux-gnu
release: 1.43.1
LLVM version: 9.0

Update: the same bug exists in String::replace_range.

@jonas-schievink jonas-schievink added C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 15, 2020
@hanna-kruppe
Copy link
Contributor

Since no allocation (String or otherwise) can be usize::MAX bytes long, this range is necessarily out of bounds and should panic. It's probably hard to match the panic message of other out-of-bounds conditions, but for a start we could use n.checked_add(1).unwrap() instead of n + 1 to get overflow checking (which is disabled by default in release mode, and users basically always get a release libstd).

BTW, the same overflow is lurking in the computation of start, e.g. when draining (Bound::Excluded(usize::MAX), Bound::Unbounded).

@estebank estebank added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label May 15, 2020
@bodil
Copy link
Author

bodil commented May 15, 2020

I've also just encountered it in String::replace_range.

@estebank
Copy link
Contributor

The same bug is present in String, Vec, VecDeque and proc_macro_server.

@estebank
Copy link
Contributor

Nominating for discussion to see how we want to fix this (there are two or three alternatives).

@spastorino spastorino added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label May 21, 2020
@spastorino
Copy link
Member

Assigning P-high as discussed as part of the Prioritization Working Group process and removing I-prioritize.

@spastorino spastorino added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels May 21, 2020
@spastorino
Copy link
Member

This was discussed during today's weekly meeting. It was decided that now is @rust-lang/libs call. Tagging again as T-libs, leaving I-nomination for libs team and removing T-compiler and libs-impl.

@spastorino spastorino added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 21, 2020
@pnkfelix
Copy link
Member

also, I started a topic on the #t-libs zulip stream for this.

@Shnatsel
Copy link
Member

Since no allocation (String or otherwise) can be usize::MAX bytes long, this range is necessarily out of bounds and should panic.

Using .saturating_add(1) instead of +1 would still panic without introducing an extra branch. Are there any blockers still, or should I go ahead and open a PR with this change?

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Jul 29, 2020

I don't think saturating_add(1) will compile to something branch-free in most mainstream architectures (with the notable exception of ARM/AArch64 and only referring to scalar code, in SIMD ISAs it's more common). As for blockers, as far as I can see @estebank never really spelled out what non-panicky "DWIM" semantics they have in mind exactly, but I suppose if they still care then they can also bring it up on the PR. Everyone else seemed on board with panicking?

@KodrAus
Copy link
Contributor

KodrAus commented Oct 30, 2020

We discussed this in the recent Libs meeting and felt that treating this case like an out-of-bounds panic was the most appropriate direction.

@tmiasko
Copy link
Contributor

tmiasko commented Oct 30, 2020

This was fixed in that manner by #75207.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. P-high High priority T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants