mirror of
https://github.com/openai/codex.git
synced 2026-04-28 08:34:54 +00:00
3.4 KiB
3.4 KiB
PR #2747: Bug fix: clone of incoming_tx can lead to deadlock
- URL: https://github.com/openai/codex/pull/2747
- Author: unship
- Created: 2025-08-27 03:21:58 UTC
- Updated: 2025-08-29 02:57:33 UTC
- Changes: +0/-1, Files changed: 1, Commits: 3
Description
POC code
use tokio::sync::mpsc;
use std::time::Duration;
#[tokio::main]
async fn main() {
println!("=== Test 1: Simulating original MCP server pattern ===");
test_original_pattern().await;
}
async fn test_original_pattern() {
println!("Testing the original pattern from MCP server...");
// Create channel - this simulates the original incoming_tx/incoming_rx
let (tx, mut rx) = mpsc::channel::<String>(10);
// Task 1: Simulates stdin reader that will naturally terminate
let stdin_task = tokio::spawn({
let tx_clone = tx.clone();
async move {
println!(" stdin_task: Started, will send 3 messages then exit");
for i in 0..3 {
let msg = format!("Message {}", i);
if tx_clone.send(msg.clone()).await.is_err() {
println!(" stdin_task: Receiver dropped, exiting");
break;
}
println!(" stdin_task: Sent {}", msg);
tokio::time::sleep(Duration::from_millis(300)).await;
}
println!(" stdin_task: Finished (simulating EOF)");
// tx_clone is dropped here
}
});
// Task 2: Simulates message processor
let processor_task = tokio::spawn(async move {
println!(" processor_task: Started, waiting for messages");
while let Some(msg) = rx.recv().await {
println!(" processor_task: Processing {}", msg);
tokio::time::sleep(Duration::from_millis(100)).await;
}
println!(" processor_task: Finished (channel closed)");
});
// Task 3: Simulates stdout writer or other background task
let background_task = tokio::spawn(async move {
for i in 0..2 {
tokio::time::sleep(Duration::from_millis(500)).await;
println!(" background_task: Tick {}", i);
}
println!(" background_task: Finished");
});
println!(" main: Original tx is still alive here");
println!(" main: About to call tokio::join! - will this deadlock?");
// This is the pattern from the original code
let _ = tokio::join!(stdin_task, processor_task, background_task);
}
Full Diff
diff --git a/codex-rs/mcp-server/src/lib.rs b/codex-rs/mcp-server/src/lib.rs
index aaf3e31441..702cb50183 100644
--- a/codex-rs/mcp-server/src/lib.rs
+++ b/codex-rs/mcp-server/src/lib.rs
@@ -63,7 +63,6 @@ pub async fn run_main(
// Task: read from stdin, push to `incoming_tx`.
let stdin_reader_handle = tokio::spawn({
- let incoming_tx = incoming_tx.clone();
async move {
let stdin = io::stdin();
let reader = BufReader::new(stdin);
Review Comments
codex-rs/mcp-server/src/lib.rs
- Created: 2025-08-29 02:15:30 UTC | Link: https://github.com/openai/codex/pull/2747#discussion_r2308950877
@@ -63,7 +63,7 @@ pub async fn run_main(
// Task: read from stdin, push to `incoming_tx`.
let stdin_reader_handle = tokio::spawn({
- let incoming_tx = incoming_tx.clone();
+ let incoming_tx = incoming_tx;
Can we just remove this line rather than self-assign?