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

chore: removing unnecessary arc in scoped threads implementation #125731

Closed

Conversation

tvallotton
Copy link
Contributor

The Arc shouldn't needed because the scoped threads are allowed to borrow from the outer 'scope, which the lifetime of ScopeData should already satisfy.

The Arc isn't needed because the scoped threads are
allowed to borrow from the outer 'scope, which the lifetime
of scopedata should already satisfy.
@rustbot
Copy link
Collaborator

rustbot commented May 29, 2024

r? @jhpratt

rustbot has assigned @jhpratt.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 29, 2024
@ChrisDenton
Copy link
Contributor

Why was an Arc added? What has changed since then?

@tvallotton
Copy link
Contributor Author

Why was an Arc added? What has changed since then?

I have no idea. I was reading the code, and went to discord to ask why was an Arc being used here for no reason. Someone told me "if you think its unnecessary, remove it and make a PR", so I did. The tests pass so it must be fine.

@ChrisDenton
Copy link
Contributor

Not necessarily. I would do a git blame on the code (there's also a "blame" button in the github UI) and look for the commit that added it.

@bugadani
Copy link
Contributor

#98503 introduced the Arc to fix a data race.

@@ -136,14 +136,12 @@ pub fn scope<'env, F, T>(f: F) -> T
where
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
{
// We put the `ScopeData` into an `Arc` so that other threads can finish their
Copy link
Member

Choose a reason for hiding this comment

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

that justification seems fairly clear, so you'd need to show why it's incorrect

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Idk, it wasn't clear to me when I read it. The way I saw it, the scoped data outlives the place where it is joined, so it seemed reasonable a reference should outlive it.

Copy link
Member

Choose a reason for hiding this comment

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

improving the comment would be a nice improvement then :)

Copy link
Contributor

@workingjubilee workingjubilee May 29, 2024

Choose a reason for hiding this comment

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

for an example of how the lifetimes involved can be very complex and counterintuitive even in the scoped thread case, see:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

improving the comment would be a nice improvement then :)

Yeah, definitely.

@ChrisDenton
Copy link
Contributor

cc @RalfJung it would be good to have a test for #98498 so the Arc doesn't get removed when it's still needed

@Nilstrieb
Copy link
Member

I'm not sure that such a test that fails outside Miri would be possible. I wonder if Miri catches this, how exactly do you test std under Miri locally?

@RalfJung
Copy link
Member

how exactly do you test std under Miri locally?

./x.py miri std :)
But most of std fails because it uses APIs Miri does not support. So ./x.py miri std -- thread:: or so would work.

The reproducer in the original issue (#98498) is an std doctest. rustc CI runs these std doctests in Miri. So CI should catch when this breaks again -- but PR CI doesn't, and also this is a concurrency issue so it may be somewhat random whether it gets detected or not.

@RalfJung
Copy link
Member

./x.py miri std -- thread:: on this PR does indeed catch the issue, first try.

...........error: Undefined Behavior: not granting access to tag <3430156> because that would remove [SharedReadOnly for <3471498>] which is strongly protected because it is an argument of call 757088
    --> /home/r/src/rust/rustc.2/library/core/src/ptr/mod.rs:537:1
     |
537  | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <3430156> because that would remove [SharedReadOnly for <3471498>] which is strongly protected because it is an argument of call 757088
     |
     = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows 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
help: <3430156> was created here, as the root tag for alloc1430378
    --> library/std/src/thread/tests.rs:393:9
     |
393  | /         thread::scope(|s| {
394  | |             for _ in 0..5 {
395  | |                 s.spawn(|| a_bool.load(Ordering::Relaxed));
396  | |             }
...    |
400  | |             }
401  | |         });
     | |__________^
help: <3471498> is this argument
    --> library/std/src/thread/scoped.rs:60:49
     |
60   |     pub(super) fn decrement_num_running_threads(&self, panic: bool) {
     |                                                 ^^^^^
     = note: BACKTRACE (of the first span) on thread `thread::tests::`:
     = note: inside `core::ptr::drop_in_place::<thread::scoped::Scope<'_, '_>> - shim(Some(thread::scoped::Scope<'_, '_>))` at /home/r/src/rust/rustc.2/library/core/src/ptr/mod.rs:537:1: 537:56
note: inside `thread::tests::scope_join_race`
    --> library/std/src/thread/tests.rs:393:9
     |
393  | /         thread::scope(|s| {
394  | |             for _ in 0..5 {
395  | |                 s.spawn(|| a_bool.load(Ordering::Relaxed));
396  | |             }
...    |
400  | |             }
401  | |         });
     | |__________^
note: inside closure
    --> library/std/src/thread/tests.rs:389:21
     |
387  | #[test]
     | ------- in this procedural macro expansion
388  | #[cfg(miri)] // relies on Miri's data race detector
389  | fn scope_join_race() {
     |                     ^
     |
    ::: /home/r/src/rust/rustc.2/library/core/src/macros/mod.rs:1636:5
     |
1636 |     pub macro test($item:item) {
     |     -------------- in this expansion of `#[test]`

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: test failed, to rerun pass `-p std --lib`

@RalfJung
Copy link
Member

RalfJung commented May 29, 2024

Oh in fact that's exactly a regression test for #98498 that triggered the UB. :)
So, the only extra thing we could do here is have a copy of this test in the Miri test suite, then it would be caught already during PR CI and not just with bors. (Or probably it'd make more sense to move the test than to copy it.)

@workingjubilee
Copy link
Contributor

@tvallotton Would you be so kind as to make sure the test in question lands in miri's test suite in this PR?

@RalfJung
Copy link
Member

RalfJung commented May 29, 2024 via email

@tvallotton
Copy link
Contributor Author

@tvallotton Would you be so kind as to make sure the test in question lands in miri's test suite in this PR?

I could but if I don't think I can do it today.

@RalfJung
Copy link
Member

RalfJung commented May 29, 2024

@rust-lang/miri how do we feel about having this test in our test suite?

Personally I think we should not add this test to our test suite. It takes close to 10s to run on my laptop, making it one of the slowest tests we have. I don't think that's something I want to wait for every time I do ./miri test during Miri development. The Miri test suite should focus on finding bugs in Miri, not std. We carry some tests for things that came up in core/std, but those are cheap and cost basically no time. But for cases where the test is expensive (scope_join_race, arc_drop_dereferenceable_race) I have deliberately not added them to the Miri testsuite.

@workingjubilee
Copy link
Contributor

workingjubilee commented May 29, 2024

Oh that's slower than I was expecting, I was hoping it was something it could be feasible to run only a few iterations of but 10s for 100 means that's still 100millis for that test, just for 1 iteration.

@oli-obk
Copy link
Contributor

oli-obk commented May 29, 2024

I don't think it's useful to have it in the miri test suite. As long as it exists elsewhere, so it will eventually fail under miri, and the documentation references the test, we have all the coverage we need

@workingjubilee
Copy link
Contributor

Ah, making sure references exist then sounds like a good idea. We can make sure the comments here reference that test at least.

@saethlin
Copy link
Member

saethlin commented May 30, 2024

I agree that adding this slow test to Miri's test suite is not a net benefit here.

@jhpratt
Copy link
Member

jhpratt commented May 31, 2024

r? libs

I don't really have the context here, and it seems as if others know what's necessary. Feel free to claim directly.

@rustbot rustbot assigned Nilstrieb and unassigned jhpratt May 31, 2024
@Nilstrieb
Copy link
Member

I don't think there's much gained from adding this specific test to the Miri test suite to make it run in PR CI. If the problem is that std Miri tests aren't running in PR CI, they should be made to run in PR CI. I don't know if we can afford that, that would be a question for infra.
I'm not sure it's worth it, since I don't think it comes up that often, but it certainly wouldn't hurt the development experience either.

As for this PR, let's improve the comment to be clearer and link the test in it, to make sure someone in the future knows exactly what's going on.

@RalfJung
Copy link
Member

RalfJung commented May 31, 2024

Running Miri on core, alloc, std currently takes about 50-60min I think. So that's not something we can easily add to PR CI. std is run on multiple targets, but that will only save 10-20 minutes I think.

@Nilstrieb
Copy link
Member

@rustbot author

@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 4, 2024
@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jun 4, 2024
@tvallotton
Copy link
Contributor Author

Should I just go on and close it?

@Nilstrieb
Copy link
Member

you're welcome to improve the comment such that you won't be confused next time, but you can also just close it if you don't want to

@tvallotton tvallotton closed this Jun 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants