Skip to content

Commit 8744627

Browse files
committed
fix: add process-wide mutex to stderr capture to prevent races
Signed-off-by: danbugs <danilochiarlone@gmail.com>
1 parent 3009d4b commit 8744627

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

host/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2215,7 +2215,11 @@ pub fn run_vm_capture_output(
22152215
let setup_time = setup_start.elapsed();
22162216

22172217
// Redirect stderr to a temp file before the call phase
2218-
let capture_file = std::env::temp_dir().join(format!("hl-capture-{}", std::process::id()));
2218+
let capture_file = std::env::temp_dir().join(format!(
2219+
"hl-capture-{}-{:?}",
2220+
std::process::id(),
2221+
std::thread::current().id()
2222+
));
22192223
let capture = stderr_capture::Capture::redirect_to_file(&capture_file)?;
22202224

22212225
// Phase 2: restore + call — application runs and produces output

host/src/stderr_capture.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,37 @@ mod imp {
1010
use nix::unistd;
1111
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
1212
use std::path::Path;
13+
use std::sync::{Mutex, MutexGuard};
14+
15+
/// Process-wide lock protecting fd 2 (stderr) manipulation.
16+
/// Held from `redirect_to_file` until `restore` to prevent concurrent
17+
/// VMs from racing on dup2.
18+
static STDERR_LOCK: Mutex<()> = Mutex::new(());
1319

1420
pub struct Capture {
1521
original_stderr: OwnedFd,
22+
_guard: MutexGuard<'static, ()>,
1623
}
1724

1825
impl Capture {
1926
pub fn redirect_to_file(path: &Path) -> Result<Self> {
27+
let guard = STDERR_LOCK
28+
.lock()
29+
.unwrap_or_else(|poisoned| poisoned.into_inner());
2030
let capture_fd = std::fs::File::create(path)?.into_raw_fd();
2131
let original_stderr_raw = unistd::dup(2)?;
2232
unistd::dup2(capture_fd, 2)?;
2333
unistd::close(capture_fd)?;
2434
let original_stderr = unsafe { OwnedFd::from_raw_fd(original_stderr_raw) };
25-
Ok(Self { original_stderr })
35+
Ok(Self {
36+
original_stderr,
37+
_guard: guard,
38+
})
2639
}
2740

2841
pub fn restore(self) -> Result<()> {
2942
unistd::dup2(self.original_stderr.as_raw_fd(), 2)?;
43+
// _guard is dropped here, releasing STDERR_LOCK
3044
Ok(())
3145
}
3246
}

0 commit comments

Comments
 (0)