Skip to content

Commit a00fe20

Browse files
committed
Add a thread-safe implementation of Process.currentDirectoryURL
posix_spawn_file_actions_addchdir_np is the official way to set the working directory of a spawned process and is supported on both macOS and glibc (Linux, etc.). This makes Process.currentDirectoryURL thread-safe, as the current approach will result in the working directory being nondeterministically assigned when spawning processes across multiple threads, using different working directories.
1 parent a12c7d1 commit a00fe20

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

Sources/CoreFoundation/CFPlatform.c

+17
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,23 @@ CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_
22742274
return posix_spawn_file_actions_addclose((posix_spawn_file_actions_t *)file_actions, filedes);
22752275
}
22762276

2277+
CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path) {
2278+
// Standardized as posix_spawn_file_actions_addchdir in POSIX.1-2024 (June 2024)
2279+
// _np variant available in:
2280+
// - Solaris 11.3 (October 2015)
2281+
// - Glibc 2.29 (February 2019)
2282+
// - macOS 10.15 (October 2019)
2283+
// - musl 1.1.24 (October 2019)
2284+
// - FreeBSD 13.1 (May 2022)
2285+
// - Android 14 (October 2023)
2286+
// standard variant available in:
2287+
// - Solaris 11.4 (August 2018)
2288+
// - NetBSD 10.0 (March 2024)
2289+
// missing in:
2290+
// - OpenBSD
2291+
return posix_spawn_file_actions_addchdir_np((posix_spawn_file_actions_t *)file_actions, path);
2292+
}
2293+
22772294
CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *_Nullable const argv[_Nullable _CF_RESTRICT], char *_Nullable const envp[_Nullable _CF_RESTRICT]) {
22782295
return posix_spawn(pid, path, (posix_spawn_file_actions_t *)file_actions, (posix_spawnattr_t *)attrp, argv, envp);
22792296
}

Sources/CoreFoundation/include/ForSwiftFoundationOnly.h

+1
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ CF_EXPORT int _CFPosixSpawnFileActionsDestroy(_CFPosixSpawnFileActionsRef file_a
725725
CF_EXPORT void _CFPosixSpawnFileActionsDealloc(_CFPosixSpawnFileActionsRef file_actions);
726726
CF_EXPORT int _CFPosixSpawnFileActionsAddDup2(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes);
727727
CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_actions, int filedes);
728+
CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path);
728729
#ifdef __cplusplus
729730
CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT path, _CFPosixSpawnFileActionsRef file_actions, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp, char *const argv[], char *const envp[]);
730731
#else

Sources/Foundation/Process.swift

+3-11
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,9 @@ open class Process: NSObject, @unchecked Sendable {
925925
for fd in addclose.filter({ $0 >= 0 }) {
926926
try _throwIfPosixError(_CFPosixSpawnFileActionsAddClose(fileActions, fd))
927927
}
928+
if let dir = currentDirectoryURL?.path {
929+
try _throwIfPosixError(_CFPosixSpawnFileActionsChdir(fileActions, dir))
930+
}
928931

929932
#if canImport(Darwin) || os(Android) || os(OpenBSD)
930933
var spawnAttrs: posix_spawnattr_t? = nil
@@ -947,17 +950,6 @@ open class Process: NSObject, @unchecked Sendable {
947950
}
948951
#endif
949952

950-
let fileManager = FileManager()
951-
let previousDirectoryPath = fileManager.currentDirectoryPath
952-
if let dir = currentDirectoryURL?.path, !fileManager.changeCurrentDirectoryPath(dir) {
953-
throw _NSErrorWithErrno(errno, reading: true, url: currentDirectoryURL)
954-
}
955-
956-
defer {
957-
// Reset the previous working directory path.
958-
_ = fileManager.changeCurrentDirectoryPath(previousDirectoryPath)
959-
}
960-
961953
// Launch
962954
var pid = pid_t()
963955

0 commit comments

Comments
 (0)