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

Capturing thread output during tests interacts poorly with global thread pools #113080

Open
alexcrichton opened this issue Jun 27, 2023 · 0 comments
Labels
A-libtest Area: #[test] related C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@alexcrichton
Copy link
Member

Tests by default capture their output of stdout/stderr using a libstd-private API, and these handles used to capture output are inherited by spawned threads of each test. This inheriting behavior interacts poorly for programs which have something akin to a global thread pool. Any test may spawn a thread added to the global thread pool and then that global thread's output is permanently fused to the original test that spawned it.

This ends up resulting in confusing situations such as rayon-rs/rayon#1066 where test panic messages are entirely swallowed by default and not displayed at all. A smaller (contrived) example of this is:

use std::sync::{Condvar, Mutex};
use std::thread::JoinHandle;

static LOCK: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
static COND: Condvar = Condvar::new();

#[test]
fn foo() {
    *LOCK.lock().unwrap() = Some(std::thread::spawn(|| {
        panic!("this message will not be seen");
    }));
    COND.notify_one();
}

#[test]
fn bar() {
    let lock = LOCK.lock().unwrap();
    let mut lock = COND.wait_while(lock, |state| state.is_none()).unwrap();
    if let Err(e) = lock.take().unwrap().join() {
        std::panic::resume_unwind(e);
    }
}

where here the foo test spawns some work which is then "resumed" in bar, but the panic message isn't actually displayed anywhere:

$ cargo test
    Finished test [unoptimized + debuginfo] target(s) in 0.01s
     Running unittests src/main.rs (target/debug/deps/wat-fc5370c265a065b8)

running 2 tests
test foo ... ok
test bar ... FAILED

failures:

failures:
    bar

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--bin wat`

I'm not sure that there's really an easy fix for this, so this is probably more of a "shouting into the void" style of issue, but figured I might as well open it after taking the time to investigate it anyway.

@jyn514 jyn514 added A-libtest Area: #[test] related C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-libtest Area: #[test] related C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
Status: No status
Development

No branches or pull requests

2 participants