mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
Fix shell timeout race on Windows
This commit is contained in:
@@ -1888,10 +1888,10 @@ fn realtime_tool_ok_command() -> Vec<String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
vec![
|
||||
"powershell.exe".to_string(),
|
||||
"-NoProfile".to_string(),
|
||||
"-Command".to_string(),
|
||||
"[Console]::Write('realtime-tool-ok')".to_string(),
|
||||
"cmd.exe".to_string(),
|
||||
"/D".to_string(),
|
||||
"/C".to_string(),
|
||||
"echo|set /p dummy=realtime-tool-ok".to_string(),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1241,15 +1241,20 @@ async fn consume_output(
|
||||
};
|
||||
tokio::pin!(expiration_wait);
|
||||
let (exit_status, timed_out) = tokio::select! {
|
||||
biased;
|
||||
_ = &mut expiration_wait => {
|
||||
if let Some(exit_status) = child.try_wait()? {
|
||||
(exit_status, false)
|
||||
} else {
|
||||
kill_child_process_group(&mut child)?;
|
||||
child.start_kill()?;
|
||||
(synthetic_exit_status(EXIT_CODE_SIGNAL_BASE + TIMEOUT_CODE), true)
|
||||
}
|
||||
}
|
||||
status_result = child.wait() => {
|
||||
let exit_status = status_result?;
|
||||
(exit_status, false)
|
||||
}
|
||||
_ = &mut expiration_wait => {
|
||||
kill_child_process_group(&mut child)?;
|
||||
child.start_kill()?;
|
||||
(synthetic_exit_status(EXIT_CODE_SIGNAL_BASE + TIMEOUT_CODE), true)
|
||||
}
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
kill_child_process_group(&mut child)?;
|
||||
child.start_kill()?;
|
||||
|
||||
@@ -291,6 +291,51 @@ async fn exec_full_buffer_capture_ignores_expiration() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn exec_expiration_observes_already_exited_child_before_timing_out() -> Result<()> {
|
||||
#[cfg(windows)]
|
||||
let command = vec![
|
||||
"cmd.exe".to_string(),
|
||||
"/D".to_string(),
|
||||
"/C".to_string(),
|
||||
"echo|set /p dummy=hello".to_string(),
|
||||
];
|
||||
#[cfg(not(windows))]
|
||||
let command = vec!["printf".to_string(), "hello".to_string()];
|
||||
|
||||
let cancel_token = CancellationToken::new();
|
||||
cancel_token.cancel();
|
||||
let output = exec(
|
||||
ExecParams {
|
||||
command,
|
||||
cwd: codex_utils_absolute_path::AbsolutePathBuf::current_dir()?,
|
||||
expiration: ExecExpiration::Cancellation(cancel_token),
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
env: std::env::vars().collect(),
|
||||
network: None,
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: false,
|
||||
justification: None,
|
||||
arg0: None,
|
||||
},
|
||||
SandboxType::None,
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
/*windows_sandbox_filesystem_overrides*/ None,
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
/*stdout_stream*/ None,
|
||||
Some(Box::new(|| std::thread::sleep(Duration::from_secs(1)))),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(output.stdout.from_utf8_lossy().text, "hello");
|
||||
assert_eq!(output.exit_status.code(), Some(0));
|
||||
assert!(!output.timed_out);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn exec_full_buffer_capture_keeps_io_drain_timeout_when_descendant_holds_pipe_open()
|
||||
|
||||
Reference in New Issue
Block a user