rust-lang / rust-lang/rust

`rustc_thread_pool::scope` can return before all scoped jobs finish if a later panic value panics on drop

Open
#157,969 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug needs-triage
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

scope can unwind before a slower scoped job has finished.
scope() should not return by unwind until every scoped job has completed but scope() returns after about 100 ms while the slower job finishes later and writes through the scoped borrow

That violates this property

Repro below:

---cargo
[package]
edition = "2021"
[dependencies]
rustc-rayon-core = "0.5.1" # or rustc_thread_pool = { path = "/path/to/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/rustc-src/rust/compiler/rustc_thread_pool" }
---

use std::panic::{self, AssertUnwindSafe};
use std::thread;
use std::time::Duration;

use rustc_thread_pool::ThreadPoolBuilder;

struct PanicOnDrop;

impl Drop for PanicOnDrop {
    fn drop(&mut self) {
        panic!("drop panic");
    }
}

fn main() {
    panic::set_hook(Box::new(|_| {}));

    let pool = ThreadPoolBuilder::new().num_threads(2).build().unwrap();
    let mut data = Box::new(0usize);

    let result = panic::catch_unwind(AssertUnwindSafe(|| {
        pool.scope(|scope| {
            let slot: &mut usize = &mut data;
            scope.spawn(|_| panic!("job panic"));
            scope.spawn(move |_| {
                thread::sleep(Duration::from_millis(350));
                *slot = 1;
            });
            thread::sleep(Duration::from_millis(100));
            panic::panic_any(PanicOnDrop);
        });
    }));

    println!("caught={}", result.is_err());
    std::mem::forget(result);

    drop(data);
    thread::sleep(Duration::from_millis(500));
}

$ RUSTFLAGS=-Zsanitizer=address ASAN_OPTIONS=halt_on_error=1 cargo +nightly -Zscript -q main.rs
caught=true
=================================================================
==33659==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000150 at pc 0x0001043a0c60 bp 0x00016bc65400 sp 0x00016bc653f8
WRITE of size 8 at 0x602000000150 thread T1
    #0 0x0001043a0c5c in _RNCNCNCNvCs9umYB8D3b62_4main4mains_00s_0B7_ main.rs:39
    #1 0x0001043a6694 in _RNCNCINvMNtCsa2rZXaaU2X0_10rayon_core5scopeNtB7_5Scope5spawnNCNCNCNvCs9umYB8D3b62_4main4mains_00s_0E00B14_ mod.rs:531
    #2 0x0001043a417c in _RNvXsn_NtNtCs3LtjeOwDatA_4core5panic11unwind_safeINtB5_16AssertUnwindSafeNCNCINvMNtCsa2rZXaaU2X0_10rayon_core5scopeNtB1h_5Scope5spawnNCNCNCNvCs9umYB8D3b62_4main4mains_00s_0E00EINtNtNtB9_3ops8function6FnOnceuE9call_onceB2f_ unwind_safe.rs:275
    #3 0x0001043a446c in _RINvNvNtCs2RIEs2EU4b4_3std9panicking12catch_unwind7do_callINtNtNtCs3LtjeOwDatA_4core5panic11unwind_safe16AssertUnwindSafeNCNCINvMNtCsa2rZXaaU2X0_10rayon_core5scopeNtB23_5Scope5spawnNCNCNCNvCs9umYB8D3b62_4main4mains_00s_0E00EuEB31_ panicking.rs:575
    #4 0x0001043a1f30 in __rust_try+0x1c (main:arm64+0x100001f30)
    #5 0x0001043a1a44 in _RINvNtCs2RIEs2EU4b4_3std9panicking12catch_unwinduINtNtNtCs3LtjeOwDatA_4core5panic11unwind_safe16AssertUnwindSafeNCNCINvMNtCsa2rZXaaU2X0_10rayon_core5scopeNtB1U_5Scope5spawnNCNCNCNvCs9umYB8D3b62_4main4mains_00s_0E00EEB2S_ panicking.rs:543... 

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in compiler/rustc_thread_pool/src/scope/mod.rs, especially the property around lines 293-296, and run the provided reproducer with the rustc-rayon-core dependency. Trace how scope handles multiple panics and the later panic value's drop. Done means scope does not unwind until every scoped job has completed, avoiding the demonstrated late write through the scoped borrow.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.