Skip to content

Commit 7d52c8b

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 ca3669e commit 7d52c8b

File tree

3 files changed

+11
-11
lines changed

3 files changed

+11
-11
lines changed

CoreFoundation/Base.subproj/CFPlatform.c

+7
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,13 @@ CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_
22512251
return posix_spawn_file_actions_addclose((posix_spawn_file_actions_t *)file_actions, filedes);
22522252
}
22532253

2254+
CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path) {
2255+
if (__builtin_available(macOS 10.15, *)) {
2256+
return posix_spawn_file_actions_addchdir_np((posix_spawn_file_actions_t *)file_actions, path);
2257+
}
2258+
return ENOTSUP; // unreachable
2259+
}
2260+
22542261
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]) {
22552262
return posix_spawn(pid, path, (posix_spawn_file_actions_t *)file_actions, (posix_spawnattr_t *)attrp, argv, envp);
22562263
}

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

+1
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ CF_EXPORT int _CFPosixSpawnFileActionsDestroy(_CFPosixSpawnFileActionsRef file_a
736736
CF_EXPORT void _CFPosixSpawnFileActionsDealloc(_CFPosixSpawnFileActionsRef file_actions);
737737
CF_EXPORT int _CFPosixSpawnFileActionsAddDup2(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes);
738738
CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_actions, int filedes);
739+
CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path);
739740
#ifdef __cplusplus
740741
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[]);
741742
#else

Sources/Foundation/Process.swift

+3-11
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,9 @@ open class Process: NSObject {
923923
for fd in addclose.filter({ $0 >= 0 }) {
924924
try _throwIfPosixError(_CFPosixSpawnFileActionsAddClose(fileActions, fd))
925925
}
926+
if let dir = currentDirectoryURL?.path {
927+
try _throwIfPosixError(_CFPosixSpawnFileActionsChdir(fileActions, dir))
928+
}
926929

927930
#if canImport(Darwin) || os(Android) || os(OpenBSD)
928931
var spawnAttrs: posix_spawnattr_t? = nil
@@ -945,17 +948,6 @@ open class Process: NSObject {
945948
}
946949
#endif
947950

948-
let fileManager = FileManager()
949-
let previousDirectoryPath = fileManager.currentDirectoryPath
950-
if let dir = currentDirectoryURL?.path, !fileManager.changeCurrentDirectoryPath(dir) {
951-
throw _NSErrorWithErrno(errno, reading: true, url: currentDirectoryURL)
952-
}
953-
954-
defer {
955-
// Reset the previous working directory path.
956-
fileManager.changeCurrentDirectoryPath(previousDirectoryPath)
957-
}
958-
959951
// Launch
960952
var pid = pid_t()
961953
guard _CFPosixSpawn(&pid, launchPath, fileActions, &spawnAttrs, argv, envp) == 0 else {

0 commit comments

Comments
 (0)