forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#136682 - ChrisDenton:move-win-proc-tests, r…
…=joboet Move two windows process tests to tests/ui Spawning processes from std unit tests is not something it's well suited for so moving them into tests/ui is more robust and means we don't need to hack around `cmd.exe`. Follow up to rust-lang#136630
- Loading branch information
Showing
3 changed files
with
169 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Test that windows `creation_flags` extension to `Command` works. | ||
|
||
//@ run-pass | ||
//@ only-windows | ||
//@ needs-subprocess | ||
|
||
use std::env; | ||
use std::os::windows::process::CommandExt; | ||
use std::process::{Command, exit}; | ||
|
||
fn main() { | ||
if env::args().skip(1).any(|s| s == "--child") { | ||
child(); | ||
} else { | ||
parent(); | ||
} | ||
} | ||
|
||
fn parent() { | ||
let exe = env::current_exe().unwrap(); | ||
|
||
// Use the DETACH_PROCESS to create a subprocess that isn't attached to the console. | ||
// The subprocess's exit status will be 0 if it's detached. | ||
let status = Command::new(&exe) | ||
.arg("--child") | ||
.creation_flags(DETACH_PROCESS) | ||
.spawn() | ||
.unwrap() | ||
.wait() | ||
.unwrap(); | ||
assert_eq!(status.code(), Some(0)); | ||
|
||
// Try without DETACH_PROCESS to ensure this test works. | ||
let status = Command::new(&exe).arg("--child").spawn().unwrap().wait().unwrap(); | ||
assert_eq!(status.code(), Some(1)); | ||
} | ||
|
||
// exits with 1 if the console is attached or 0 otherwise | ||
fn child() { | ||
// Get the attached console's code page. | ||
// This will fail (return 0) if no console is attached. | ||
let has_console = GetConsoleCP() != 0; | ||
exit(has_console as i32); | ||
} | ||
|
||
// Windows API definitions. | ||
const DETACH_PROCESS: u32 = 0x00000008; | ||
#[link(name = "kernel32")] | ||
unsafe extern "system" { | ||
safe fn GetConsoleCP() -> u32; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Tests proc thread attributes by spawning a process with a custom parent process, | ||
// then comparing the parent process ID with the expected parent process ID. | ||
|
||
//@ run-pass | ||
//@ only-windows | ||
//@ needs-subprocess | ||
//@ edition: 2021 | ||
|
||
#![feature(windows_process_extensions_raw_attribute)] | ||
|
||
use std::os::windows::io::AsRawHandle; | ||
use std::os::windows::process::{CommandExt, ProcThreadAttributeList}; | ||
use std::process::{Child, Command}; | ||
use std::{env, mem, ptr, thread, time}; | ||
|
||
// Make a best effort to ensure child processes always exit. | ||
struct ProcessDropGuard(Child); | ||
impl Drop for ProcessDropGuard { | ||
fn drop(&mut self) { | ||
let _ = self.0.kill(); | ||
} | ||
} | ||
|
||
fn main() { | ||
if env::args().skip(1).any(|s| s == "--child") { | ||
child(); | ||
} else { | ||
parent(); | ||
} | ||
} | ||
|
||
fn parent() { | ||
let exe = env::current_exe().unwrap(); | ||
|
||
let (fake_parent_id, child_parent_id) = { | ||
// Create a process to be our fake parent process. | ||
let fake_parent = Command::new(&exe).arg("--child").spawn().unwrap(); | ||
let fake_parent = ProcessDropGuard(fake_parent); | ||
let parent_handle = fake_parent.0.as_raw_handle(); | ||
|
||
// Create another process with the parent process set to the fake. | ||
let mut attribute_list = ProcThreadAttributeList::build() | ||
.attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_handle) | ||
.finish() | ||
.unwrap(); | ||
let child = | ||
Command::new(&exe).arg("--child").spawn_with_attributes(&mut attribute_list).unwrap(); | ||
let child = ProcessDropGuard(child); | ||
|
||
// Return the fake's process id and the child's parent's id. | ||
(process_info(&fake_parent.0).process_id(), process_info(&child.0).parent_id()) | ||
}; | ||
|
||
assert_eq!(fake_parent_id, child_parent_id); | ||
} | ||
|
||
// A process that stays running until killed. | ||
fn child() { | ||
// Don't wait forever if something goes wrong. | ||
thread::sleep(time::Duration::from_secs(60)); | ||
} | ||
|
||
fn process_info(child: &Child) -> PROCESS_BASIC_INFORMATION { | ||
unsafe { | ||
let mut info: PROCESS_BASIC_INFORMATION = mem::zeroed(); | ||
let result = NtQueryInformationProcess( | ||
child.as_raw_handle(), | ||
ProcessBasicInformation, | ||
ptr::from_mut(&mut info).cast(), | ||
mem::size_of_val(&info).try_into().unwrap(), | ||
ptr::null_mut(), | ||
); | ||
assert_eq!(result, 0); | ||
info | ||
} | ||
} | ||
|
||
// Windows API | ||
mod winapi { | ||
#![allow(nonstandard_style)] | ||
use std::ffi::c_void; | ||
|
||
pub type HANDLE = *mut c_void; | ||
type NTSTATUS = i32; | ||
type PROCESSINFOCLASS = i32; | ||
|
||
pub const ProcessBasicInformation: i32 = 0; | ||
pub const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; | ||
#[repr(C)] | ||
pub struct PROCESS_BASIC_INFORMATION { | ||
pub ExitStatus: NTSTATUS, | ||
pub PebBaseAddress: *mut (), | ||
pub AffinityMask: usize, | ||
pub BasePriority: i32, | ||
pub UniqueProcessId: usize, | ||
pub InheritedFromUniqueProcessId: usize, | ||
} | ||
impl PROCESS_BASIC_INFORMATION { | ||
pub fn parent_id(&self) -> usize { | ||
self.InheritedFromUniqueProcessId | ||
} | ||
pub fn process_id(&self) -> usize { | ||
self.UniqueProcessId | ||
} | ||
} | ||
|
||
#[link(name = "ntdll")] | ||
extern "system" { | ||
pub fn NtQueryInformationProcess( | ||
ProcessHandle: HANDLE, | ||
ProcessInformationClass: PROCESSINFOCLASS, | ||
ProcessInformation: *mut c_void, | ||
ProcessInformationLength: u32, | ||
ReturnLength: *mut u32, | ||
) -> NTSTATUS; | ||
} | ||
} | ||
use winapi::*; |