@@ -229,7 +229,6 @@ func spawnExecutable(
229
229
return pid
230
230
}
231
231
}
232
-
233
232
#elseif os(Windows)
234
233
return try _withStartupInfoEx ( attributeCount: 1 ) { startupInfo in
235
234
func inherit( _ fileHandle: borrowing FileHandle ) throws -> HANDLE ? {
@@ -285,6 +284,14 @@ func spawnExecutable(
285
284
let commandLine = _escapeCommandLine ( CollectionOfOne ( executablePath) + arguments)
286
285
let environ = environment. map { " \( $0. key) = \( $0. value) " } . joined ( separator: " \0 " ) + " \0 \0 "
287
286
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
+
288
295
// On Windows, a process holds a reference to its current working
289
296
// directory, which prevents other processes from deleting it. This causes
290
297
// code to fail if it tries to set the working directory to a temporary
@@ -305,34 +312,32 @@ func spawnExecutable(
305
312
flags |= DWORD ( CREATE_SUSPENDED)
306
313
#endif
307
314
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
+ }
327
333
328
334
#if DEBUG
329
- // Resume the process.
330
- _ = ResumeThread ( processInfo. hThread!)
335
+ // Resume the process.
336
+ _ = ResumeThread ( processInfo. hThread!)
331
337
#endif
332
338
333
- _ = CloseHandle ( processInfo. hThread)
334
- return processInfo. hProcess!
335
- }
339
+ _ = CloseHandle ( processInfo. hThread)
340
+ return processInfo. hProcess!
336
341
}
337
342
}
338
343
}
0 commit comments