#![warn(clippy::zombie_processes)] #![allow(clippy::if_same_then_else, clippy::ifs_same_cond, clippy::needless_return)] use std::process::{Child, Command, ExitStatus}; fn main() { { // Check that #[expect] works #[expect(clippy::zombie_processes)] let mut x = Command::new("").spawn().unwrap(); } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes x.kill(); x.id(); } { let mut x = Command::new("").spawn().unwrap(); x.wait().unwrap(); // OK } { let x = Command::new("").spawn().unwrap(); x.wait_with_output().unwrap(); // OK } { let mut x = Command::new("").spawn().unwrap(); x.try_wait().unwrap(); // OK } { let mut x = Command::new("").spawn().unwrap(); let mut r = &mut x; r.wait().unwrap(); // OK, not calling `.wait()` directly on `x` but through `r` -> `x` } { let mut x = Command::new("").spawn().unwrap(); process_child(x); // OK, other function might call `.wait()` so assume it does } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes let v = &x; // (allow shared refs is fine because one cannot call `.wait()` through that) } // https://github.com/rust-lang/rust-clippy/pull/11476#issuecomment-1718456033 // Unconditionally exiting the process in various ways (should not lint) { let mut x = Command::new("").spawn().unwrap(); std::process::exit(0); } { let mut x = Command::new("").spawn().unwrap(); std::process::abort(); // same as above, but abort instead of exit } { let mut x = Command::new("").spawn().unwrap(); if true { /* nothing */ } std::process::abort(); // still unconditionally exits } // Conditionally exiting // It should assume that it might not exit and still lint { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { std::process::exit(0); } } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { while false {} // Calling `exit()` after leaving a while loop should still be linted. std::process::exit(0); } } { let mut x = { Command::new("").spawn().unwrap() }; x.wait().unwrap(); } { struct S { c: Child, } let mut s = S { c: Command::new("").spawn().unwrap(), }; s.c.wait().unwrap(); } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { return; } x.wait().unwrap(); } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { x.wait().unwrap(); } } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { x.wait().unwrap(); } else { // this else block exists to test the other help message } } { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes if true { // this else block exists to test the other help message } else { x.wait().unwrap(); } } { let mut x = Command::new("").spawn().unwrap(); if true { x.wait().unwrap(); } else if true { x.wait().unwrap(); } else { x.wait().unwrap(); } } { let mut x = Command::new("").spawn().unwrap(); if true { x.wait().unwrap(); return; } x.wait().unwrap(); } { let mut x = Command::new("").spawn().unwrap(); std::thread::spawn(move || { x.wait().unwrap(); }); } } fn process_child(c: Child) { todo!() } fn return_wait() -> ExitStatus { let mut x = Command::new("").spawn().unwrap(); return x.wait().unwrap(); } mod issue14677 { use std::io; use std::process::Command; fn do_something Result<(), ()>>(f: F) { todo!() } fn foo() { let mut child = Command::new("true").spawn().unwrap(); let some_condition = true; do_something(|| { if some_condition { return Err(()); } Ok(()) }); child.kill().unwrap(); child.wait().unwrap(); } } fn issue14911() -> std::io::Result { let (mut recv, send) = std::io::pipe()?; let mut command = Command::new("ls") .stdout(send.try_clone()?) .spawn() .expect("Could not spawn new process..."); command.wait()?; Ok("".into()) }