about summary refs log tree commit diff
path: root/tests/ui/process/win-proc-thread-attributes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/process/win-proc-thread-attributes.rs')
-rw-r--r--tests/ui/process/win-proc-thread-attributes.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/tests/ui/process/win-proc-thread-attributes.rs b/tests/ui/process/win-proc-thread-attributes.rs
new file mode 100644
index 00000000000..91bb0b17e95
--- /dev/null
+++ b/tests/ui/process/win-proc-thread-attributes.rs
@@ -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::*;