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

Fix soundness issue in scoped threads. #94644

Merged
merged 4 commits into from
Mar 10, 2022

Conversation

m-ou-se
Copy link
Member

@m-ou-se m-ou-se commented Mar 5, 2022

This was discovered in #94559 (comment)

The scope() function returns when all threads are finished, but I accidentally considered a thread 'finished' before dropping their panic payload or ignored return value.

So if a thread returned (or panics with) something that in its Drop implementation still uses borrowed stuff, it goes wrong.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2a1f19ac4676cdabe43e24e536ff9358

@m-ou-se m-ou-se added A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 5, 2022
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Mar 5, 2022
@rust-highfive
Copy link
Collaborator

r? @kennytm

(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 Mar 5, 2022
@m-ou-se m-ou-se removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Mar 5, 2022
@m-ou-se m-ou-se mentioned this pull request Mar 5, 2022
10 tasks
// This is only relevant for threads that aren't join()ed, as
// join() will take the `result` and set it to None, such that
// there is nothing left to drop here.
// If this drop panics, that just results in an abort, because
Copy link
Member

Choose a reason for hiding this comment

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

Reading just this comment in isolation, I feel like it is dangerous to assume that all unwinding implementations would abort in absence of landing pads on the stack. I suspect there won't be any documented mandate for this sort of behavior anywhere.

Copy link
Member Author

@m-ou-se m-ou-se Mar 5, 2022

Choose a reason for hiding this comment

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

Maybe, but then that's a larger problem that Rust's regular threads (through std::thread::spawn) also have (and had, since like forever).

Copy link
Member Author

Choose a reason for hiding this comment

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

It's easy to fix it for both cases by adding a catch_unwind and abort here though. I'll do that in a second commit.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a second commit that fixes that issue for both scoped and regular threads. It now explicitly calls rtabort!() when dropping the thread result panics.

Copy link
Member Author

Choose a reason for hiding this comment

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

(cc rust-lang/lang-team#97, which would make this a non-issue.)

@nagisa
Copy link
Member

nagisa commented Mar 5, 2022

I wonder if there's any way to write a regression test here. I think comparing drop order between data captured by the scope and the data that refers to this captured data shouldn't he too difficult. Something like this perhaps?

struct MustDropFirst;
struct MustDropSecond<'scope>(&'scope MustDropFirst);

impl Drop for MustDropFirst { /* checks drop order between the two types */ }
impl Drop for MustDropSecond { /* checks drop order between the two types */ }

fn main() {
    let data = MustDropFirst;
    let r = &data;
    scope(|s| {
        s.spawn(move || {
            MustDropSecond(r);
        });
    });
}

The implementation LGTM either way, though.

@m-ou-se
Copy link
Member Author

m-ou-se commented Mar 5, 2022

I wonder if there's any way to write a regression test here.

It's a bit tricky, because the bug doesn't mean it gets ordered in the opposite direction, but that there's no guarantee how it gets ordered. In practice, without sleeping or a significant amount of work, the thread most likely finishes dropping the result before the main thread wakes up, making the bug invisible.

It's somewhat easy to test this with sleeping, but I'm not sure it's a great idea to have a unit test that sleeps.

Copy link
Contributor

@danielhenrymantilla danielhenrymantilla left a comment

Choose a reason for hiding this comment

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

Good catch!

library/std/src/thread/mod.rs Show resolved Hide resolved
@m-ou-se m-ou-se force-pushed the scoped-threads-drop-soundness branch from 18f5719 to b97d875 Compare March 9, 2022 10:48
@m-ou-se
Copy link
Member Author

m-ou-se commented Mar 9, 2022

@nagisa I've added a test. (And verified it fails without the changes in this PR.)

@joshtriplett
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Mar 9, 2022

📌 Commit b97d875 has been approved by joshtriplett

@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 9, 2022
@bors
Copy link
Contributor

bors commented Mar 9, 2022

⌛ Testing commit b97d875 with merge a301059c353dee85b3a3e52923c8094a9d7a02d1...

@bors
Copy link
Contributor

bors commented Mar 9, 2022

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Mar 9, 2022
@nagisa
Copy link
Member

nagisa commented Mar 9, 2022

@bors retry #94779

@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 9, 2022
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Mar 9, 2022
…ss, r=joshtriplett

Fix soundness issue in scoped threads.

This was discovered in rust-lang#94559 (comment)

The `scope()` function returns when all threads are finished, but I accidentally considered a thread 'finished' before dropping their panic payload or ignored return value.

So if a thread returned (or panics with) something that in its `Drop` implementation still uses borrowed stuff, it goes wrong.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2a1f19ac4676cdabe43e24e536ff9358
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-tools failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
.......... (60/61)
.          (61/61)


/checkout/src/test/rustdoc-gui/mobile.goml mobile... FAILED
[ERROR] (line 27) Error: Evaluation failed: assert didn't fail: for command `compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})`
Build completed unsuccessfully in 0:00:16

@m-ou-se
Copy link
Member Author

m-ou-se commented Mar 10, 2022

@bors retry

m-ou-se added a commit to m-ou-se/rust that referenced this pull request Mar 10, 2022
…ss, r=joshtriplett

Fix soundness issue in scoped threads.

This was discovered in rust-lang#94559 (comment)

The `scope()` function returns when all threads are finished, but I accidentally considered a thread 'finished' before dropping their panic payload or ignored return value.

So if a thread returned (or panics with) something that in its `Drop` implementation still uses borrowed stuff, it goes wrong.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2a1f19ac4676cdabe43e24e536ff9358
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Mar 10, 2022
…ss, r=joshtriplett

Fix soundness issue in scoped threads.

This was discovered in rust-lang#94559 (comment)

The `scope()` function returns when all threads are finished, but I accidentally considered a thread 'finished' before dropping their panic payload or ignored return value.

So if a thread returned (or panics with) something that in its `Drop` implementation still uses borrowed stuff, it goes wrong.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2a1f19ac4676cdabe43e24e536ff9358
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 10, 2022
…askrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#94440 (Better error for normalization errors from parent crates that use `#![feature(generic_const_exprs)]`)
 - rust-lang#94587 (Document new recommended use of `FromIterator::from_iter`)
 - rust-lang#94644 (Fix soundness issue in scoped threads.)
 - rust-lang#94740 (Unify impl blocks by wrapping them into a div)
 - rust-lang#94753 (Improve rustdoc book)
 - rust-lang#94796 (Allow `cargo run` instead of `cargo run -p bootstrap`)
 - rust-lang#94805 (Revert accidental stabilization)
 - rust-lang#94809 (RustWrapper: add missing include)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit f1a6777 into rust-lang:master Mar 10, 2022
@rustbot rustbot added this to the 1.61.0 milestone Mar 10, 2022
@m-ou-se m-ou-se deleted the scoped-threads-drop-soundness branch March 29, 2022 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-runtime Area: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

9 participants