Skip to content

Commit 1431037

Browse files
committed
Make a copy of the command line while I'm in here per MS docs
1 parent 670b1f8 commit 1431037

File tree

1 file changed

+30
-25
lines changed

1 file changed

+30
-25
lines changed

Sources/Testing/ExitTests/SpawnProcess.swift

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)