summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Martin <evan.martin@gmail.com>2023-12-21 15:44:15 -0800
committerEvan Martin <evan.martin@gmail.com>2023-12-21 15:44:15 -0800
commit08667f8300825b18962ea7113f9b0a7a0d0cd10c (patch)
tree8715627484b3bd3a3025bf940d9ea23abc59edfc
parent60e9a6ea8b9cbb217a420cc850e4ba051cdc755e (diff)
downloadn2-08667f8300825b18962ea7113f9b0a7a0d0cd10c.tar.gz
win: ensure thread attributes live long enough
The pointers passed in a PROC_THREAD_ATTRIBUTE_LIST must outlive the struct, so add some lifetime hackery.
-rw-r--r--src/process_win.rs30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/process_win.rs b/src/process_win.rs
index 45b9162..6b8aa17 100644
--- a/src/process_win.rs
+++ b/src/process_win.rs
@@ -6,6 +6,7 @@ use std::ffi::c_void;
use std::io::Read;
use std::os::windows::io::{FromRawHandle, OwnedHandle};
use std::os::windows::prelude::AsRawHandle;
+use std::pin::{pin, Pin};
use windows_sys::Win32::{
Foundation::*,
Security::SECURITY_ATTRIBUTES,
@@ -83,9 +84,17 @@ impl Drop for ProcessInformation {
}
}
-/// Wrapper for PROC_THREAD_ATTRIBUTE_LIST. This is a type whose size we discover at runtime.
-struct ProcThreadAttributeList(Box<[u8]>);
-impl ProcThreadAttributeList {
+/// Wrapper for PROC_THREAD_ATTRIBUTE_LIST.
+/// Per MSDN: attribute values "must persist until the attribute list is
+/// destroyed using the DeleteProcThreadAttributeList function", which is
+/// captured by the 'a lifetime.
+struct ProcThreadAttributeList<'a> {
+ /// The PROC_THREAD_ATTRIBUTE_LIST; this is a type whose size we discover at runtime.
+ raw: Box<[u8]>,
+ /// The inherit_handles pointer.
+ _marker: std::marker::PhantomData<&'a [HANDLE]>,
+}
+impl<'a> ProcThreadAttributeList<'a> {
fn new(count: usize) -> anyhow::Result<Self> {
unsafe {
let mut size = 0;
@@ -107,11 +116,15 @@ impl ProcThreadAttributeList {
{
win_bail!(InitializeProcThreadAttributeList);
}
- Ok(Self(buf))
+ Ok(Self {
+ raw: buf,
+ _marker: std::marker::PhantomData,
+ })
}
}
- fn inherit_handles(&mut self, handles: &[HANDLE]) -> anyhow::Result<()> {
+ /// Mark some handles as to be inherited.
+ fn inherit_handles(&mut self, handles: Pin<&'a [HANDLE]>) -> anyhow::Result<()> {
unsafe {
if UpdateProcThreadAttribute(
self.as_mut_ptr(),
@@ -130,11 +143,11 @@ impl ProcThreadAttributeList {
}
fn as_mut_ptr(&mut self) -> LPPROC_THREAD_ATTRIBUTE_LIST {
- self.0.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST
+ self.raw.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST
}
}
-impl Drop for ProcThreadAttributeList {
+impl<'a> Drop for ProcThreadAttributeList<'a> {
fn drop(&mut self) {
unsafe { DeleteProcThreadAttributeList(self.as_mut_ptr()) };
}
@@ -181,8 +194,9 @@ pub fn run_command(cmdline: &str, mut output_cb: impl FnMut(&[u8])) -> anyhow::R
// Safely inherit in/out handles.
// https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873
+ let handles = pin!([startup_info.StartupInfo.hStdInput, raw_pipe_write]);
let mut attrs = ProcThreadAttributeList::new(1)?;
- attrs.inherit_handles(&[startup_info.StartupInfo.hStdInput, raw_pipe_write])?;
+ attrs.inherit_handles(handles)?;
startup_info.lpAttributeList = attrs.as_mut_ptr();
let mut process_info = ProcessInformation::new();