-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
VecDeque: length 0 underflow and bogus values from pop_front(), triggered by a certain sequence of reserve(), push_back(), make_contiguous(), pop_front() #79808
Comments
I created a minimal sample: use std::collections::VecDeque;
fn ab(dq: &mut VecDeque<i32>, sz: usize) {
for i in 0..sz {
dq.push_back(i as _);
}
dq.make_contiguous();
for _ in 0..sz {
dq.pop_front();
}
}
fn main() {
let mut dq = VecDeque::with_capacity(2);
ab(&mut dq, 2);
ab(&mut dq, 3);
dbg!(dq.len()); // this is zero
dbg!(dq.pop_front()); // uaf+double frees
} |
Hmm, if it double-frees then why does Miri not catch it? |
Assigning |
Some time ago I've read somewhere that Rust stdlib VecDeque is cursed. I didn't believe them. I'm changing opinion... -.- |
This specific case doesn't double free (i32::drop is a noop), using a |
Still, this is memory-unsafe, right? |
Yes, It's still a use-after-free regardless |
This comment has been minimized.
This comment has been minimized.
@naim94a Based on my conversation with lcnr, jonas-schievink, and others on Zulip, it seems that using |
…lcnr Add another test case for rust-lang#79808 Taken from rust-lang#80293. Closes rust-lang#80293 r? `@lcnr`
Rollup of 8 pull requests Successful merges: - rust-lang#79757 (Replace tabs earlier in diagnostics) - rust-lang#80600 (Add `MaybeUninit` method `array_assume_init`) - rust-lang#80880 (Move some tests to more reasonable directories) - rust-lang#80897 (driver: Use `atty` instead of rolling our own) - rust-lang#80898 (Add another test case for rust-lang#79808) - rust-lang#80917 (core/slice: remove doc comment about scoped borrow) - rust-lang#80927 (Replace a simple `if let` with the `matches` macro) - rust-lang#80930 (fix typo in trait method mutability mismatch help) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This is my first bug report, so please correct me s if I miss anything :-)
I use VecDeque in a toy application (https://github.com/ayourtch/flex-sftp-server) which is handling external reads in a loop, and does possible partial handling of the input.
My pattern is I call reserve(N) before push_back() N times, then make_contiguous(), then doing some pop_front(). I noticed the app was behaving badly, and was able to generate a stand-alone test case which shows the bug.
The code is pretty boring and repetitive, so I put it at https://github.com/ayourtch/deq-bug/ to avoid spamming here.
Just issue "cargo run" after cloning out that code, and look for the word "BUG" within the terminal output:
According to the docs, pop_front() on an empty VecDeque should return None.
Instead, this happens:
If I set the boolean "do_reserve" to be false, thus getting rid of all the reserve() calls, I get the expected behavior:
The same happens if I set "do_make_contiguous" to false as well - so calling both functions is a prerequisite to trigger the bug.
The same thing happens in debug and release builds.
Meta
The below is the version I found it in, but thanks a lot to Steve Klabnik for also testing it on nightly and getting the same buggy behavior.
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: