Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 142 additions & 6 deletions Sources/CoreFoundation/CFPlatform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,12 @@ static int (*_CFPosixSpawnFileActionsAddDup2Impl)(_CFPosixSpawnFileActionsRef, i
static int (*_CFPosixSpawnFileActionsAddCloseImpl)(_CFPosixSpawnFileActionsRef, int);
static int (*_CFPosixSpawnImpl)(pid_t *_CF_RESTRICT, const char *_CF_RESTRICT, _CFPosixSpawnFileActionsRef, _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT, char *_Nullable const[_Nullable _CF_RESTRICT], char *_Nullable const[_Nullable _CF_RESTRICT]);

static _CFPosixSpawnAttrRef (*_CFPosixSpawnAttrAllocImpl)(void);
static int (*_CFPosixSpawnAttrInitImpl)(_CFPosixSpawnAttrRef);
static int (*_CFPosixSpawnAttrDestroyImpl)(_CFPosixSpawnAttrRef);
static void (*_CFPosixSpawnAttrDeallocImpl)(_CFPosixSpawnAttrRef);
static int (*_CFPosixSpawnAttrSetFlagsImpl)(_CFPosixSpawnAttrRef, short);

static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPost28() {
_CFPosixSpawnFileActionsRef actions = malloc(sizeof(posix_spawn_file_actions_t));
CFAssert(actions != NULL, __kCFLogAssertion, "malloc failed");
Expand All @@ -1957,6 +1963,16 @@ static void _CFPosixSpawnFileActionsDeallocImplBoth(_CFPosixSpawnFileActionsRef
free(file_actions);
}

static _CFPosixSpawnAttrRef _CFPosixSpawnAttrAllocImplPost28() {
_CFPosixSpawnAttrRef attr = malloc(sizeof(posix_spawnattr_t));
CFAssert(attr != NULL, __kCFLogAssertion, "malloc failed");
return attr;
}

static void _CFPosixSpawnAttrDeallocImplBoth(_CFPosixSpawnAttrRef attr) {
free(attr);
}

enum _CFPosixSpawnFileActionTypePre28 {
_CFPosixSpawnFileActionDup2Pre28,
_CFPosixSpawnFileActionClosePre28,
Expand All @@ -1975,6 +1991,11 @@ struct _CFPosixSpawnFileActionPre28 {
};
};

struct _CFPosixSpawnAttrPre28 {
short flags;
pid_t pgroup;
};

struct _CFPosixSpawnFileActionsPre28 {
struct _CFPosixSpawnFileActionPre28 *actions;
size_t actionsCount;
Expand All @@ -1990,6 +2011,12 @@ static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPre28() {
return actions;
}

static _CFPosixSpawnAttrRef _CFPosixSpawnAttrAllocImplPre28() {
_CFPosixSpawnAttrRef attr = calloc(1, sizeof(struct _CFPosixSpawnAttrPre28));
CFAssert(attr != NULL, __kCFLogAssertion, "malloc failed");
return attr;
}

static int _CFPosixSpawnFileActionsInitImplPre28(_CFPosixSpawnFileActionsRef file_actions) {
if (file_actions == NULL) {
return EINVAL;
Expand All @@ -2009,6 +2036,30 @@ static int _CFPosixSpawnFileActionsInitImplPre28(_CFPosixSpawnFileActionsRef fil
return 0;
}

static int _CFPosixSpawnAttrInitImplPre28(_CFPosixSpawnAttrRef spawn_attr) {
if (spawn_attr == NULL) {
return EINVAL;
}

struct _CFPosixSpawnAttrPre28 *attr = (struct _CFPosixSpawnAttrPre28 *)spawn_attr;
attr->flags = 0;
attr->pgroup = 0;

return 0;
}

static int _CFPosixSpawnAttrDestroyImplPre28(_CFPosixSpawnAttrRef spawn_attr) {
if (spawn_attr == NULL) {
return EINVAL;
}

struct _CFPosixSpawnAttrPre28 *attr = (struct _CFPosixSpawnAttrPre28 *)spawn_attr;
attr->flags = 0;
attr->pgroup = 0;

return 0;
}

static int _CFPosixSpawnFileActionsDestroyImplPre28(_CFPosixSpawnFileActionsRef file_actions) {
if (file_actions == NULL) {
return EINVAL;
Expand Down Expand Up @@ -2096,12 +2147,6 @@ static int _CFPosixSpawnFileActionsAddCloseImplPre28(_CFPosixSpawnFileActionsRef
}

static int _CFPosixSpawnImplPre28(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]) {
// TODO: We completely ignore attrp, because at the moment, the only
// invocation doesn't pass a value.
if (attrp != NULL) {
return EINVAL;
}

struct _CFPosixSpawnFileActionsPre28 *actions = (struct _CFPosixSpawnFileActionsPre28 *)file_actions;
if (actions != NULL && actions->isValid != _CFPosixSpawnFileActionsPre28Valid) {
return EINVAL;
Expand Down Expand Up @@ -2159,6 +2204,11 @@ static int _CFPosixSpawnImplPre28(pid_t *_CF_RESTRICT pid, const char *_CF_RESTR
}
}

// Apply flags
struct _CFPosixSpawnAttrPre28 *attr = (struct _CFPosixSpawnAttrPre28 *)attrp;
short flags = attr ? attr->flags : 0;
if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid(0, attr->pgroup) == -1) _exit(127);

// Perform the actions
if (actions != NULL) {
for (size_t idx = 0; idx < actions->actionsCount; idx++) {
Expand Down Expand Up @@ -2186,6 +2236,24 @@ static int _CFPosixSpawnImplPre28(pid_t *_CF_RESTRICT pid, const char *_CF_RESTR
// no need for return here
}

static int _CFPosixSpawnAttrSetFlagsImplPre28(_CFPosixSpawnAttrRef spawn_attr, short flags) {
if (spawn_attr == NULL) {
return EINVAL;
}

if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF |
POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER |
POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID)) != 0) {
return EINVAL;
}

struct _CFPosixSpawnAttrPre28 *attr = (struct _CFPosixSpawnAttrPre28 *)spawn_attr;

attr->flags = flags;

return 0;
}

static void _CFPosixSpawnInitializeCallback() {
// Let's check if the posix_spawn is present.
(void)dlerror(); // Clean up the error.
Expand All @@ -2212,6 +2280,21 @@ static void _CFPosixSpawnInitializeCallback() {
_CFPosixSpawnFileActionsAddCloseImpl = (int (*)(void *, int))dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addclose");
dlsymError = dlerror();
CFAssert1(_CFPosixSpawnFileActionsAddCloseImpl != NULL, __kCFLogAssertion, "loading posix_spawn_file_actions_addclose failed: %s", dlsymError);

_CFPosixSpawnAttrAllocImpl = _CFPosixSpawnAttrAllocImplPost28;
_CFPosixSpawnAttrDeallocImpl = _CFPosixSpawnAttrDeallocImplBoth;

_CFPosixSpawnAttrInitImpl = (int (*)(void *))dlsym(RTLD_DEFAULT, "posix_spawnattr_init");
dlsymError = dlerror();
CFAssert1(_CFPosixSpawnAttrInitImpl != NULL, __kCFLogAssertion, "loading posix_spawnattr_init failed: %s", dlsymError);

_CFPosixSpawnAttrDestroyImpl = (int (*)(void *))dlsym(RTLD_DEFAULT, "posix_spawnattr_destroy");
dlsymError = dlerror();
CFAssert1(_CFPosixSpawnAttrDestroyImpl != NULL, __kCFLogAssertion, "loading posix_spawnattr_destroy failed: %s", dlsymError);

_CFPosixSpawnAttrSetFlagsImpl = (int (*)(void *, short))dlsym(RTLD_DEFAULT, "posix_spawnattr_setflags");
dlsymError = dlerror();
CFAssert1(_CFPosixSpawnAttrSetFlagsImpl != NULL, __kCFLogAssertion, "loading posix_spawnattr_setflags failed: %s", dlsymError);
} else {
// posix_spawn_fn is not available, setup our workaround
_CFPosixSpawnFileActionsAllocImpl = _CFPosixSpawnFileActionsAllocImplPre28;
Expand All @@ -2221,6 +2304,12 @@ static void _CFPosixSpawnInitializeCallback() {
_CFPosixSpawnFileActionsAddDup2Impl = _CFPosixSpawnFileActionsAddDup2ImplPre28;
_CFPosixSpawnFileActionsAddCloseImpl = _CFPosixSpawnFileActionsAddCloseImplPre28;
_CFPosixSpawnImpl = _CFPosixSpawnImplPre28;

_CFPosixSpawnAttrAllocImpl = _CFPosixSpawnAttrAllocImplPre28;
_CFPosixSpawnAttrDeallocImpl = _CFPosixSpawnAttrDeallocImplBoth;
_CFPosixSpawnAttrInitImpl = _CFPosixSpawnFileActionsInitImplPre28;
_CFPosixSpawnAttrDestroyImpl = _CFPosixSpawnAttrDestroyImplPre28;
_CFPosixSpawnAttrSetFlagsImpl = _CFPosixSpawnAttrSetFlagsImplPre28;
}
}

Expand Down Expand Up @@ -2268,6 +2357,31 @@ CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT pa
return _CFPosixSpawnImpl(pid, path, file_actions, attrp, argv, envp);
}

CF_EXPORT _CFPosixSpawnAttrRef _CFPosixSpawnAttrAlloc() {
_CFPosixSpawnInitialize();
return _CFPosixSpawnAttrAllocImpl();
}

CF_EXPORT int _CFPosixSpawnAttrInit(_CFPosixSpawnAttrRef spawn_attr) {
_CFPosixSpawnInitialize();
return _CFPosixSpawnAttrInitImpl(spawn_attr);
}

CF_EXPORT int _CFPosixSpawnAttrDestroy(_CFPosixSpawnAttrRef spawn_attr) {
_CFPosixSpawnInitialize();
return _CFPosixSpawnAttrDestroyImpl(spawn_attr);
}

CF_EXPORT void _CFPosixSpawnAttrDealloc(_CFPosixSpawnAttrRef spawn_attr) {
_CFPosixSpawnInitialize();
_CFPosixSpawnAttrDeallocImpl(spawn_attr);
}

CF_EXPORT int _CFPosixSpawnAttrSetFlags(_CFPosixSpawnAttrRef spawn_attr, short flags) {
_CFPosixSpawnInitialize();
return _CFPosixSpawnAttrSetFlagsImpl(spawn_attr, flags);
}

#elif !TARGET_OS_WIN32 && !TARGET_OS_WASI

#include <spawn.h>
Expand Down Expand Up @@ -2332,6 +2446,28 @@ CF_EXPORT int _CFPosixSpawn(pid_t *_CF_RESTRICT pid, const char *_CF_RESTRICT pa
return posix_spawn(pid, path, (posix_spawn_file_actions_t *)file_actions, (posix_spawnattr_t *)attrp, argv, envp);
}

CF_EXPORT _CFPosixSpawnAttrRef _CFPosixSpawnAttrAlloc() {
_CFPosixSpawnAttrRef attr = malloc(sizeof(posix_spawnattr_t));
CFAssert(attr != NULL, __kCFLogAssertion, "malloc failed");
return attr;
}

CF_EXPORT int _CFPosixSpawnAttrInit(_CFPosixSpawnAttrRef spawn_attr) {
return posix_spawnattr_init((posix_spawnattr_t *)spawn_attr);
}

CF_EXPORT int _CFPosixSpawnAttrDestroy(_CFPosixSpawnAttrRef spawn_attr) {
return posix_spawnattr_destroy((posix_spawnattr_t *)spawn_attr);
}

CF_EXPORT void _CFPosixSpawnAttrDealloc(_CFPosixSpawnAttrRef spawn_attr) {
free(spawn_attr);
}

CF_EXPORT int _CFPosixSpawnAttrSetFlags(_CFPosixSpawnAttrRef spawn_attr, short flags) {
return posix_spawnattr_setflags((posix_spawnattr_t *)spawn_attr, flags);
}

#endif

#endif
5 changes: 5 additions & 0 deletions Sources/CoreFoundation/include/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,11 @@ CF_EXPORT void _CFPosixSpawnFileActionsDealloc(_CFPosixSpawnFileActionsRef file_
CF_EXPORT int _CFPosixSpawnFileActionsAddDup2(_CFPosixSpawnFileActionsRef file_actions, int filedes, int newfiledes);
CF_EXPORT int _CFPosixSpawnFileActionsAddClose(_CFPosixSpawnFileActionsRef file_actions, int filedes);
CF_EXPORT int _CFPosixSpawnFileActionsChdir(_CFPosixSpawnFileActionsRef file_actions, const char *path);
CF_EXPORT _CFPosixSpawnAttrRef _CFPosixSpawnAttrAlloc(void);
CF_EXPORT int _CFPosixSpawnAttrInit(_CFPosixSpawnAttrRef spawn_attr);
CF_EXPORT int _CFPosixSpawnAttrDestroy(_CFPosixSpawnAttrRef spawn_attr);
CF_EXPORT void _CFPosixSpawnAttrDealloc(_CFPosixSpawnAttrRef spawn_attr);
CF_EXPORT int _CFPosixSpawnAttrSetFlags(_CFPosixSpawnAttrRef spawn_attr, short flags);
#ifdef __cplusplus
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[]);
#else
Expand Down
18 changes: 8 additions & 10 deletions Sources/Foundation/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -939,21 +939,17 @@ open class Process: NSObject, @unchecked Sendable {
useFallbackChdir = false
}

#if canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD)
var spawnAttrs: posix_spawnattr_t? = nil
#else
var spawnAttrs: posix_spawnattr_t = posix_spawnattr_t()
#endif
try _throwIfPosixError(posix_spawnattr_init(&spawnAttrs))
let spawnAttrs = _CFPosixSpawnAttrAlloc()
try _throwIfPosixError(_CFPosixSpawnAttrInit(spawnAttrs))
#if os(Android)
guard var spawnAttrs else {
throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno),
userInfo: [NSURLErrorKey:self.executableURL!])
}
#endif
try _throwIfPosixError(posix_spawnattr_setflags(&spawnAttrs, .init(POSIX_SPAWN_SETPGROUP)))
var flags = Int16(POSIX_SPAWN_SETPGROUP)
#if canImport(Darwin)
try _throwIfPosixError(posix_spawnattr_setflags(&spawnAttrs, .init(POSIX_SPAWN_CLOEXEC_DEFAULT)))
flags |= Int16(POSIX_SPAWN_CLOEXEC_DEFAULT)
#else
// POSIX_SPAWN_CLOEXEC_DEFAULT is an Apple extension so emulate it.
for fd in 3 ... findMaximumOpenFD() {
Expand All @@ -965,6 +961,7 @@ open class Process: NSObject, @unchecked Sendable {
try _throwIfPosixError(_CFPosixSpawnFileActionsAddClose(fileActions, fd))
}
#endif
try _throwIfPosixError(_CFPosixSpawnAttrSetFlags(spawnAttrs, flags))

// Unsafe fallback for systems missing posix_spawn_file_actions_addchdir[_np]
// This includes Glibc versions older than 2.29 such as on Amazon Linux 2
Expand All @@ -991,11 +988,12 @@ open class Process: NSObject, @unchecked Sendable {
var pid = pid_t()

try FileManager.default._fileSystemRepresentation(withPath: launchPath, { fsRep in
guard _CFPosixSpawn(&pid, fsRep, fileActions, &spawnAttrs, argv, envp) == 0 else {
guard _CFPosixSpawn(&pid, fsRep, fileActions, spawnAttrs, argv, envp) == 0 else {
throw _NSErrorWithErrno(errno, reading: true, path: launchPath)
}
})
posix_spawnattr_destroy(&spawnAttrs)
_CFPosixSpawnAttrDestroy(spawnAttrs)
_CFPosixSpawnAttrDealloc(spawnAttrs)

// Close the write end of the input and output pipes.
if let pipe = standardInput as? Pipe {
Expand Down