Skip to content

Commit 17f466a

Browse files
committed
Ensure stdio handles are inherited on Windows
1 parent 8f0bd48 commit 17f466a

File tree

1 file changed

+41
-38
lines changed

1 file changed

+41
-38
lines changed

Sources/Testing/ExitTests/SpawnProcess.swift

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -201,50 +201,53 @@ func spawnExecutable(
201201
try inherit(standardError, as: &startupInfo.pointee.StartupInfo.hStdError)
202202
startupInfo.pointee.StartupInfo.dwFlags |= STARTF_USESTDHANDLES
203203

204-
// Forward the back channel's write end to the child process so that it can
205-
// send information back to us. Note that we don't keep the pipe open as
206-
// bidirectional, though we could if we find we need to in the future.
207-
let inheritedHandlesBuffer = UnsafeMutableBufferPointer<HANDLE?>.allocate(capacity: additionalFileHandles.count)
208-
defer {
209-
inheritedHandlesBuffer.deallocate()
210-
}
204+
// Ensure standard I/O streams and any explicitly added file handles are
205+
// inherited by the child process.
206+
var inheritedHandles = [HANDLE?](repeating: nil, count: additionalFileHandles.count + 3)
207+
try inherit(standardInput, as: &inheritedHandles[0])
208+
try inherit(standardOutput, as: &inheritedHandles[1])
209+
try inherit(standardError, as: &inheritedHandles[2])
211210
for i in 0 ..< additionalFileHandles.count {
212-
try inherit(additionalFileHandles[i].pointee, as: &inheritedHandlesBuffer[i])
211+
try inherit(additionalFileHandles[i].pointee, as: &inheritedHandles[i + 3])
213212
}
214-
_ = UpdateProcThreadAttribute(
215-
startupInfo.pointee.lpAttributeList,
216-
0,
217-
swt_PROC_THREAD_ATTRIBUTE_HANDLE_LIST(),
218-
inheritedHandlesBuffer.baseAddress!,
219-
SIZE_T(MemoryLayout<HANDLE>.stride * inheritedHandlesBuffer.count),
220-
nil,
221-
nil
222-
)
213+
inheritedHandles = inheritedHandles.compactMap(\.self)
223214

224-
let commandLine = _escapeCommandLine(CollectionOfOne(executablePath) + arguments)
225-
let environ = environment.map { "\($0.key)=\($0.value)" }.joined(separator: "\0") + "\0\0"
215+
return try inheritedHandles.withUnsafeMutableBufferPointer { inheritedHandles in
216+
_ = UpdateProcThreadAttribute(
217+
startupInfo.pointee.lpAttributeList,
218+
0,
219+
swt_PROC_THREAD_ATTRIBUTE_HANDLE_LIST(),
220+
inheritedHandles.baseAddress!,
221+
SIZE_T(MemoryLayout<HANDLE>.stride * inheritedHandles.count),
222+
nil,
223+
nil
224+
)
226225

227-
return try commandLine.withCString(encodedAs: UTF16.self) { commandLine in
228-
try environ.withCString(encodedAs: UTF16.self) { environ in
229-
var processInfo = PROCESS_INFORMATION()
226+
let commandLine = _escapeCommandLine(CollectionOfOne(executablePath) + arguments)
227+
let environ = environment.map { "\($0.key)=\($0.value)" }.joined(separator: "\0") + "\0\0"
230228

231-
guard CreateProcessW(
232-
nil,
233-
.init(mutating: commandLine),
234-
nil,
235-
nil,
236-
true, // bInheritHandles
237-
DWORD(CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT),
238-
.init(mutating: environ),
239-
nil,
240-
startupInfo.pointer(to: \.StartupInfo)!,
241-
&processInfo
242-
) else {
243-
throw Win32Error(rawValue: GetLastError())
244-
}
245-
_ = CloseHandle(processInfo.hThread)
229+
return try commandLine.withCString(encodedAs: UTF16.self) { commandLine in
230+
try environ.withCString(encodedAs: UTF16.self) { environ in
231+
var processInfo = PROCESS_INFORMATION()
246232

247-
return processInfo.hProcess!
233+
guard CreateProcessW(
234+
nil,
235+
.init(mutating: commandLine),
236+
nil,
237+
nil,
238+
true, // bInheritHandles
239+
DWORD(CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT),
240+
.init(mutating: environ),
241+
nil,
242+
startupInfo.pointer(to: \.StartupInfo)!,
243+
&processInfo
244+
) else {
245+
throw Win32Error(rawValue: GetLastError())
246+
}
247+
_ = CloseHandle(processInfo.hThread)
248+
249+
return processInfo.hProcess!
250+
}
248251
}
249252
}
250253
}

0 commit comments

Comments
 (0)