Skip to content

Commit 050d2f2

Browse files
authored
Reset default signal handlers on child processes before spawning them. (#732)
On platforms that use `posix_spawn()`, we should take care to reset the signal handlers of child processes to their defaults, right? Or should this be valid? ```swift signal(SIGABRT, SIG_IGN) await #expect(exitsWith: .success) { raise(SIGABRT) // does nothing because we set it to SIG_IGN in the parent exit(0) } ``` ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 81c537c commit 050d2f2

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

Diff for: Sources/Testing/ExitTests/SpawnProcess.swift

+34-11
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,44 @@ func spawnExecutable(
5454

5555
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD)
5656
return try withUnsafeTemporaryAllocation(of: P<posix_spawn_file_actions_t>.self, capacity: 1) { fileActions in
57-
guard 0 == posix_spawn_file_actions_init(fileActions.baseAddress!) else {
57+
let fileActions = fileActions.baseAddress!
58+
guard 0 == posix_spawn_file_actions_init(fileActions) else {
5859
throw CError(rawValue: swt_errno())
5960
}
6061
defer {
61-
_ = posix_spawn_file_actions_destroy(fileActions.baseAddress!)
62+
_ = posix_spawn_file_actions_destroy(fileActions)
6263
}
6364

6465
return try withUnsafeTemporaryAllocation(of: P<posix_spawnattr_t>.self, capacity: 1) { attrs in
65-
guard 0 == posix_spawnattr_init(attrs.baseAddress!) else {
66+
let attrs = attrs.baseAddress!
67+
guard 0 == posix_spawnattr_init(attrs) else {
6668
throw CError(rawValue: swt_errno())
6769
}
6870
defer {
69-
_ = posix_spawnattr_destroy(attrs.baseAddress!)
71+
_ = posix_spawnattr_destroy(attrs)
72+
}
73+
74+
// Flags to set on the attributes value before spawning the process.
75+
var flags = CShort(0)
76+
77+
// Reset signal handlers to their defaults.
78+
withUnsafeTemporaryAllocation(of: sigset_t.self, capacity: 1) { noSignals in
79+
let noSignals = noSignals.baseAddress!
80+
sigemptyset(noSignals)
81+
posix_spawnattr_setsigmask(attrs, noSignals)
82+
flags |= CShort(POSIX_SPAWN_SETSIGMASK)
83+
}
84+
withUnsafeTemporaryAllocation(of: sigset_t.self, capacity: 1) { allSignals in
85+
let allSignals = allSignals.baseAddress!
86+
sigfillset(allSignals)
87+
posix_spawnattr_setsigdefault(attrs, allSignals);
88+
flags |= CShort(POSIX_SPAWN_SETSIGDEF)
7089
}
7190

7291
// Do not forward standard I/O.
73-
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDIN_FILENO, "/dev/null", O_RDONLY, 0)
74-
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)
75-
_ = posix_spawn_file_actions_addopen(fileActions.baseAddress!, STDERR_FILENO, "/dev/null", O_WRONLY, 0)
92+
_ = posix_spawn_file_actions_addopen(fileActions, STDIN_FILENO, "/dev/null", O_RDONLY, 0)
93+
_ = posix_spawn_file_actions_addopen(fileActions, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)
94+
_ = posix_spawn_file_actions_addopen(fileActions, STDERR_FILENO, "/dev/null", O_WRONLY, 0)
7695

7796
#if os(Linux) || os(FreeBSD)
7897
var highestFD = CInt(0)
@@ -83,7 +102,7 @@ func spawnExecutable(
83102
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")
84103
}
85104
#if SWT_TARGET_OS_APPLE
86-
_ = posix_spawn_file_actions_addinherit_np(fileActions.baseAddress!, fd)
105+
_ = posix_spawn_file_actions_addinherit_np(fileActions, fd)
87106
#elseif os(Linux) || os(FreeBSD)
88107
highestFD = max(highestFD, fd)
89108
#endif
@@ -92,17 +111,21 @@ func spawnExecutable(
92111

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

125+
// Set flags; make sure to keep this call below any code that might modify
126+
// the flags mask!
127+
_ = posix_spawnattr_setflags(attrs, flags)
128+
106129
var argv: [UnsafeMutablePointer<CChar>?] = [strdup(executablePath)]
107130
argv += arguments.lazy.map { strdup($0) }
108131
argv.append(nil)
@@ -121,7 +144,7 @@ func spawnExecutable(
121144
}
122145

123146
var pid = pid_t()
124-
guard 0 == posix_spawn(&pid, executablePath, fileActions.baseAddress!, attrs.baseAddress, argv, environ) else {
147+
guard 0 == posix_spawn(&pid, executablePath, fileActions, attrs, argv, environ) else {
125148
throw CError(rawValue: swt_errno())
126149
}
127150
return pid

0 commit comments

Comments
 (0)