Skip to content

Reset default signal handlers on child processes before spawning them. #732

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Sep 27, 2024
Merged
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
45 changes: 34 additions & 11 deletions Sources/Testing/ExitTests/SpawnProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,44 @@ func spawnExecutable(

#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
return try withUnsafeTemporaryAllocation(of: P<posix_spawn_file_actions_t>.self, capacity: 1) { fileActions in
guard 0 == posix_spawn_file_actions_init(fileActions.baseAddress!) else {
let fileActions = fileActions.baseAddress!
guard 0 == posix_spawn_file_actions_init(fileActions) else {
throw CError(rawValue: swt_errno())
}
defer {
_ = posix_spawn_file_actions_destroy(fileActions.baseAddress!)
_ = posix_spawn_file_actions_destroy(fileActions)
}

return try withUnsafeTemporaryAllocation(of: P<posix_spawnattr_t>.self, capacity: 1) { attrs in
guard 0 == posix_spawnattr_init(attrs.baseAddress!) else {
let attrs = attrs.baseAddress!
guard 0 == posix_spawnattr_init(attrs) else {
throw CError(rawValue: swt_errno())
}
defer {
_ = posix_spawnattr_destroy(attrs.baseAddress!)
_ = posix_spawnattr_destroy(attrs)
}

// Flags to set on the attributes value before spawning the process.
var flags = CShort(0)

// Reset signal handlers to their defaults.
withUnsafeTemporaryAllocation(of: sigset_t.self, capacity: 1) { noSignals in
let noSignals = noSignals.baseAddress!
sigemptyset(noSignals)
posix_spawnattr_setsigmask(attrs, noSignals)
flags |= CShort(POSIX_SPAWN_SETSIGMASK)
}
withUnsafeTemporaryAllocation(of: sigset_t.self, capacity: 1) { allSignals in
let allSignals = allSignals.baseAddress!
sigfillset(allSignals)
posix_spawnattr_setsigdefault(attrs, allSignals);
flags |= CShort(POSIX_SPAWN_SETSIGDEF)
}

// Do not forward standard I/O.
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDIN_FILENO, "/dev/null", O_RDONLY, 0)
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDERR_FILENO, "/dev/null", O_WRONLY, 0)
_ = posix_spawn_file_actions_addopen(fileActions, STDIN_FILENO, "/dev/null", O_RDONLY, 0)
_ = posix_spawn_file_actions_addopen(fileActions, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)
_ = posix_spawn_file_actions_addopen(fileActions, STDERR_FILENO, "/dev/null", O_WRONLY, 0)

#if os(Linux) || os(FreeBSD)
var highestFD = CInt(0)
Expand All @@ -83,7 +102,7 @@ func spawnExecutable(
throw SystemError(description: "A child process inherit a file handle without an associated file descriptor. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new")
}
#if SWT_TARGET_OS_APPLE
_ = posix_spawn_file_actions_addinherit_np(fileActions.baseAddress!, fd)
_ = posix_spawn_file_actions_addinherit_np(fileActions, fd)
#elseif os(Linux) || os(FreeBSD)
highestFD = max(highestFD, fd)
#endif
Expand All @@ -92,17 +111,21 @@ func spawnExecutable(

#if SWT_TARGET_OS_APPLE
// Close all other file descriptors open in the parent.
_ = posix_spawnattr_setflags(attrs.baseAddress!, CShort(POSIX_SPAWN_CLOEXEC_DEFAULT))
flags |= CShort(POSIX_SPAWN_CLOEXEC_DEFAULT)
#elseif os(Linux) || os(FreeBSD)
// This platform doesn't have POSIX_SPAWN_CLOEXEC_DEFAULT, but we can at
// least close all file descriptors higher than the highest inherited one.
// We are assuming here that the caller didn't set FD_CLOEXEC on any of
// these file descriptors.
_ = swt_posix_spawn_file_actions_addclosefrom_np(fileActions.baseAddress!, highestFD + 1)
_ = swt_posix_spawn_file_actions_addclosefrom_np(fileActions, highestFD + 1)
#else
#warning("Platform-specific implementation missing: cannot close unused file descriptors")
#endif

// Set flags; make sure to keep this call below any code that might modify
// the flags mask!
_ = posix_spawnattr_setflags(attrs, flags)

var argv: [UnsafeMutablePointer<CChar>?] = [strdup(executablePath)]
argv += arguments.lazy.map { strdup($0) }
argv.append(nil)
Expand All @@ -121,7 +144,7 @@ func spawnExecutable(
}

var pid = pid_t()
guard 0 == posix_spawn(&pid, executablePath, fileActions.baseAddress!, attrs.baseAddress, argv, environ) else {
guard 0 == posix_spawn(&pid, executablePath, fileActions, attrs, argv, environ) else {
throw CError(rawValue: swt_errno())
}
return pid
Expand Down