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

Revert Vec::spare_capacity_mut impl to prevent pointers invalidation #82564

Merged
merged 4 commits into from
Mar 4, 2021

Conversation

WaffleLapkin
Copy link
Member

The implementation was changed in #79015.

Later it was pointed out that the implementation invalidates pointers to the buffer (initialized elements) by creating a unique reference to the buffer. This PR reverts the implementation.

r? @RalfJung

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 26, 2021
@RalfJung
Copy link
Member

Thanks! The implementation looks good, but we should also add a testcase in this function.

Something like this should do it:

    // spare_capacity_mut
    v.spare_capacity_mut();
    assert_eq!(*v0, 13);

@WaffleLapkin
Copy link
Member Author

@RalfJung I've tried adding the test, but it fails under miri.

Backtrace

; RUST_SRC="../rust" ./run-test.sh alloc -- vec::test_stable_pointers
A libstd for Miri is now available in `/home/waffle/.cache/miri/HOST`.
   Compiling alloc_miri_test v0.0.0 (/home/waffle/projects/repos/miri-test-libstd/alloc_miri_test)
    Finished test [unoptimized + debuginfo] target(s) in 2.16s
     Running unittests (/home/waffle/projects/repos/miri-test-libstd/target/x86_64-unknown-linux-gnu/debug/deps/alloc_miri_test-6e6a55ec61be2275)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 251 filtered out

     Running ../liballoc/tests/lib.rs (/home/waffle/projects/repos/miri-test-libstd/target/x86_64-unknown-linux-gnu/debug/deps/collectionstests-8d70d32833968b04)

running 1 test
test vec::test_stable_pointers ... error: Undefined Behavior: trying to reborrow for SharedReadOnly at alloc935527, but parent tag <2398216> does not have an appropriate item in the borrow stack
    --> alloc_miri_test/../liballoc/tests/vec.rs:1696:5
     |
1696 |     assert_eq!(*v0, 13);
     |     ^^^^^^^^^^^^^^^^^^^^ trying to reborrow for SharedReadOnly at alloc935527, but parent tag <2398216> does not have an appropriate item in the borrow stack
     |
     = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental
     = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

     = note: inside `vec::test_stable_pointers` at /home/waffle/projects/repos/rust/library/core/src/macros/mod.rs:37:16
note: inside closure at alloc_miri_test/../liballoc/tests/vec.rs:1615:1
    --> alloc_miri_test/../liballoc/tests/vec.rs:1615:1
     |
1615 | / fn test_stable_pointers() {
1616 | |     /// Pull an element from the iterator, then drop it.
1617 | |     /// Useful to cover both the `next` and `drop` paths of an iterator.
1618 | |     fn next_then_drop<I: Iterator>(mut i: I) {
...    |
1700 | |     assert_eq!(v[0], 0);
1701 | | }
     | |_^
     = note: inside `<[closure@alloc_miri_test/../liballoc/tests/vec.rs:1615:1: 1701:2] as std::ops::FnOnce<()>>::call_once - shim` at /home/waffle/projects/repos/rust/library/core/src/ops/function.rs:227:5
     = note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/waffle/projects/repos/rust/library/core/src/ops/function.rs:227:5
     = note: inside `test::__rust_begin_short_backtrace::<fn()>` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:568:5
     = note: inside closure at /home/waffle/projects/repos/rust/library/test/src/lib.rs:559:30
     = note: inside `<[closure@test::run_test::{closure#2}] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/waffle/projects/repos/rust/library/core/src/ops/function.rs:227:5
     = note: inside `<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /home/waffle/projects/repos/rust/library/alloc/src/boxed.rs:1546:9
     = note: inside `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /home/waffle/projects/repos/rust/library/std/src/panic.rs:344:9
     = note: inside `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/waffle/projects/repos/rust/library/std/src/panicking.rs:379:40
     = note: inside `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>>` at /home/waffle/projects/repos/rust/library/std/src/panicking.rs:343:19
     = note: inside `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/waffle/projects/repos/rust/library/std/src/panic.rs:431:14
     = note: inside `test::run_test_in_process` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:590:18
     = note: inside closure at /home/waffle/projects/repos/rust/library/test/src/lib.rs:487:39
     = note: inside `test::run_test::run_test_inner` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:523:13
     = note: inside `test::run_test` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:556:28
     = note: inside `test::run_tests::<[closure@test::run_tests_console::{closure#2}]>` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:302:13
     = note: inside `test::run_tests_console` at /home/waffle/projects/repos/rust/library/test/src/console.rs:289:5
     = note: inside `test::test_main` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:123:15
     = note: inside `test::test_main_static` at /home/waffle/projects/repos/rust/library/test/src/lib.rs:142:5
     = note: inside `main`
     = note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/waffle/projects/repos/rust/library/core/src/ops/function.rs:227:5
     = note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /home/waffle/projects/repos/rust/library/std/src/sys_common/backtrace.rs:125:18
     = note: inside closure at /home/waffle/projects/repos/rust/library/std/src/rt.rs:66:18
     = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /home/waffle/projects/repos/rust/library/core/src/ops/function.rs:259:13
     = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/waffle/projects/repos/rust/library/std/src/panicking.rs:379:40
     = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /home/waffle/projects/repos/rust/library/std/src/panicking.rs:343:19
     = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/waffle/projects/repos/rust/library/std/src/panic.rs:431:14
     = note: inside `std::rt::lang_start_internal` at /home/waffle/projects/repos/rust/library/std/src/rt.rs:51:25
     = note: inside `std::rt::lang_start::<()>` at /home/waffle/projects/repos/rust/library/std/src/rt.rs:65:5
     = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

error: test failed, to rerun pass '--test collectionstests'

I would assume that the unique reference to the same allocation somewhat invalidates the pointer, but I'm not familiar enough with stacked borrows to be sure 😅

@RalfJung
Copy link
Member

RalfJung commented Mar 2, 2021

It still fails even with this PR? Uh... interesting. I might have to check out your branch and test locally, but it could be a few days until I have the time for that.

Is line 1696 the new assert one that you added?

@RalfJung
Copy link
Member

RalfJung commented Mar 2, 2021

You could run with -Zmiri-track-pointer-tag=2398216 to learn a bit more about what happens to that tag.

@WaffleLapkin
Copy link
Member Author

It still fails even with this PR?

Oh, well. Turns out, it's not.

When I run the test with -Zmiri-track-pointer-tag=2398216 I've noticed that the old implementation was used - in the call stack there was a call to std::vec::Vec::<i32>::split_at_spare_mut which this PR should have removed. Though I've also seen warnings about new implementation (when tried changing it), so for some reason the new implementation was compiled, but not used...

I assume there was a problem with caching, because after I run this:

; rm -rf liballoc
; rm -rf miri-test-libstd
; rm -rf ~/.cache/miri/
; rm -rf target

Test started passing.


I've also changed split_at_spare_mut implementation, trying to make it safer/more readable, hope it's ok.

@RalfJung
Copy link
Member

RalfJung commented Mar 3, 2021

I've also changed split_at_spare_mut implementation, trying to make it safer/more readable, hope it's ok.

Uh, so now I have to understand that function's implementation as well to review this PR.^^
Can you describe in which way it is safer now?

EDIT: Ah, as_mut_ptr_range is the key. Not sure if it's that much better but it's certainly not worse so whatever.^^

@RalfJung
Copy link
Member

RalfJung commented Mar 3, 2021

Aside from that comment nit, LGTM. Thanks!

@WaffleLapkin
Copy link
Member Author

WaffleLapkin commented Mar 3, 2021

Uh, so now I have to understand that function's implementation as well to review this PR.^^

Yeah, sorry 😅

Can you describe in which way it is safer now?

It reuses safe method (as_mut_ptr_range), instead of reimplementing essentially the same thing using unsafe.

EDIT: ooops, I'm a bit slow :p

@RalfJung
Copy link
Member

RalfJung commented Mar 3, 2021

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Mar 3, 2021

📌 Commit 950f121 has been approved by RalfJung

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 3, 2021
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Mar 4, 2021
…lfJung

Revert `Vec::spare_capacity_mut` impl to prevent pointers invalidation

The implementation was changed in rust-lang#79015.

Later it was [pointed out](rust-lang#81944 (comment)) that the implementation invalidates pointers to the buffer (initialized elements) by creating a unique reference to the buffer. This PR reverts the implementation.

r? `@RalfJung`
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Mar 4, 2021
…lfJung

Revert `Vec::spare_capacity_mut` impl to prevent pointers invalidation

The implementation was changed in rust-lang#79015.

Later it was [pointed out](rust-lang#81944 (comment)) that the implementation invalidates pointers to the buffer (initialized elements) by creating a unique reference to the buffer. This PR reverts the implementation.

r? ``@RalfJung``
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 4, 2021
Rollup of 8 pull requests

Successful merges:

 - rust-lang#80527 (Make rustdoc lints a tool lint instead of built-in)
 - rust-lang#82310 (Load rustdoc's JS search index on-demand.)
 - rust-lang#82315 (Improve page load performance in rustdoc)
 - rust-lang#82564 (Revert `Vec::spare_capacity_mut` impl to prevent pointers invalidation)
 - rust-lang#82697 (Fix stabilization version of move_ref_pattern)
 - rust-lang#82717 (Account for macros when suggesting adding lifetime)
 - rust-lang#82740 (Fix commit detected when using `download-rustc`)
 - rust-lang#82744 (Pass `CrateNum` by value instead of by reference)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 290117f into rust-lang:master Mar 4, 2021
@rustbot rustbot added this to the 1.52.0 milestone Mar 4, 2021
@WaffleLapkin WaffleLapkin deleted the revert_spare_mut branch March 4, 2021 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants