@@ -229,7 +229,6 @@ func spawnExecutable(
229229 return pid
230230 }
231231 }
232-
233232#elseif os(Windows)
234233 return try _withStartupInfoEx ( attributeCount: 1 ) { startupInfo in
235234 func inherit( _ fileHandle: borrowing FileHandle ) throws -> HANDLE ? {
@@ -285,6 +284,14 @@ func spawnExecutable(
285284 let commandLine = _escapeCommandLine ( CollectionOfOne ( executablePath) + arguments)
286285 let environ = environment. map { " \( $0. key) = \( $0. value) " } . joined ( separator: " \0 " ) + " \0 \0 "
287286
287+ // CreateProcessW() may modify the command line argument, so we must make
288+ // a mutable copy of it. (environ is also passed as a mutable raw pointer,
289+ // but it is not documented as actually being mutated.)
290+ let commandLineCopy = commandLine. withCString ( encodedAs: UTF16 . self) { _wcsdup ( $0) }
291+ defer {
292+ free ( commandLineCopy)
293+ }
294+
288295 // On Windows, a process holds a reference to its current working
289296 // directory, which prevents other processes from deleting it. This causes
290297 // code to fail if it tries to set the working directory to a temporary
@@ -305,34 +312,32 @@ func spawnExecutable(
305312 flags |= DWORD ( CREATE_SUSPENDED)
306313#endif
307314
308- return try commandLine. withCString ( encodedAs: UTF16 . self) { commandLine in
309- try environ. withCString ( encodedAs: UTF16 . self) { environ in
310- try workingDirectoryPath. withCString ( encodedAs: UTF16 . self) { workingDirectoryPath in
311- var processInfo = PROCESS_INFORMATION ( )
312-
313- guard CreateProcessW (
314- nil ,
315- . init( mutating: commandLine) ,
316- nil ,
317- nil ,
318- true , // bInheritHandles
319- flags,
320- . init( mutating: environ) ,
321- workingDirectoryPath,
322- startupInfo. pointer ( to: \. StartupInfo) !,
323- & processInfo
324- ) else {
325- throw Win32Error ( rawValue: GetLastError ( ) )
326- }
315+ return try environ. withCString ( encodedAs: UTF16 . self) { environ in
316+ try workingDirectoryPath. withCString ( encodedAs: UTF16 . self) { workingDirectoryPath in
317+ var processInfo = PROCESS_INFORMATION ( )
318+
319+ guard CreateProcessW (
320+ nil ,
321+ commandLineCopy,
322+ nil ,
323+ nil ,
324+ true , // bInheritHandles
325+ flags,
326+ . init( mutating: environ) ,
327+ workingDirectoryPath,
328+ startupInfo. pointer ( to: \. StartupInfo) !,
329+ & processInfo
330+ ) else {
331+ throw Win32Error ( rawValue: GetLastError ( ) )
332+ }
327333
328334#if DEBUG
329- // Resume the process.
330- _ = ResumeThread ( processInfo. hThread!)
335+ // Resume the process.
336+ _ = ResumeThread ( processInfo. hThread!)
331337#endif
332338
333- _ = CloseHandle ( processInfo. hThread)
334- return processInfo. hProcess!
335- }
339+ _ = CloseHandle ( processInfo. hThread)
340+ return processInfo. hProcess!
336341 }
337342 }
338343 }
0 commit comments