Skip to content

[WIP] Adopt lifetime annotations for owned resources. #1224

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ extension Array where Element == PackageDescription.SwiftSetting {

.enableUpcomingFeature("InferIsolatedConformances"),

.enableExperimentalFeature("Lifetimes"),

// When building as a package, the macro plugin always builds as an
// executable rather than a library.
.define("SWT_NO_LIBRARY_MACRO_PLUGINS"),
Expand Down
4 changes: 1 addition & 3 deletions Sources/Testing/ABI/EntryPoints/SwiftPMEntryPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ public func __swiftPMEntryPoint(passing args: __CommandLineArguments_v0? = nil)
// Ensure that stdout is line- rather than block-buffered. Swift Package
// Manager reroutes standard I/O through pipes, so we tend to end up with
// block-buffered streams.
FileHandle.stdout.withUnsafeCFILEHandle { stdout in
_ = setvbuf(stdout, nil, _IOLBF, Int(BUFSIZ))
}
_ = setvbuf(FileHandle.stdout.unsafeCFILEHandle, nil, _IOLBF, Int(BUFSIZ))
#endif

return await entryPoint(passing: args, eventHandler: nil)
Expand Down
12 changes: 4 additions & 8 deletions Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -700,13 +700,9 @@ extension ExitTest {
/// file handle could not be converted to a string.
private static func _makeEnvironmentVariable(for fileHandle: borrowing FileHandle) -> String? {
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
return fileHandle.withUnsafePOSIXFileDescriptor { fd in
fd.map(String.init(describing:))
}
fileHandle.unsafePOSIXFileDescriptor.map(String.init(describing:))
#elseif os(Windows)
return fileHandle.withUnsafeWindowsHANDLE { handle in
handle.flatMap { String(describing: UInt(bitPattern: $0)) }
}
fileHandle.unsafeWindowsHANDLE.flatMap { String(describing: UInt(bitPattern: $0)) }
#else
#warning("Platform-specific implementation missing: additional file descriptors unavailable")
return nil
Expand Down Expand Up @@ -879,15 +875,15 @@ extension ExitTest {
var stdoutWriteEnd: FileHandle?
if exitTest._observedValues.contains(\.standardOutputContent) {
try FileHandle.makePipe(readEnd: &stdoutReadEnd, writeEnd: &stdoutWriteEnd)
stdoutWriteEnd?.withUnsafeCFILEHandle { stdout in
if let stdout = stdoutWriteEnd?.unsafeCFILEHandle {
_ = setvbuf(stdout, nil, _IOLBF, Int(BUFSIZ))
}
}
var stderrReadEnd: FileHandle?
var stderrWriteEnd: FileHandle?
if exitTest._observedValues.contains(\.standardErrorContent) {
try FileHandle.makePipe(readEnd: &stderrReadEnd, writeEnd: &stderrWriteEnd)
stderrWriteEnd?.withUnsafeCFILEHandle { stderr in
if let stderr = stderrWriteEnd?.unsafeCFILEHandle {
_ = setvbuf(stderr, nil, _IONBF, Int(BUFSIZ))
}
}
Expand Down
65 changes: 31 additions & 34 deletions Sources/Testing/ExitTests/SpawnProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,34 +120,32 @@ func spawnExecutable(
// Forward standard I/O streams and any explicitly added file handles.
var highestFD = max(STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)
func inherit(_ fileHandle: borrowing FileHandle, as standardFD: CInt? = nil) throws {
try fileHandle.withUnsafePOSIXFileDescriptor { fd in
guard let fd else {
throw SystemError(description: "A child process cannot inherit a file handle without an associated file descriptor. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new")
}
if let standardFD, standardFD != fd {
_ = posix_spawn_file_actions_adddup2(fileActions, fd, standardFD)
} else {
guard let fd = fileHandle.unsafePOSIXFileDescriptor else {
throw SystemError(description: "A child process cannot inherit a file handle without an associated file descriptor. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new")
}
if let standardFD, standardFD != fd {
_ = posix_spawn_file_actions_adddup2(fileActions, fd, standardFD)
} else {
#if SWT_TARGET_OS_APPLE
_ = posix_spawn_file_actions_addinherit_np(fileActions, fd)
_ = posix_spawn_file_actions_addinherit_np(fileActions, fd)
#else
// posix_spawn_file_actions_adddup2() will automatically clear
// FD_CLOEXEC after forking but before execing even if the old and
// new file descriptors are equal. This behavior is supported by
// Glibc ≥ 2.29, FreeBSD, OpenBSD, and Android (Bionic) and is
// standardized in POSIX.1-2024 (see https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_adddup2.html
// and https://www.austingroupbugs.net/view.php?id=411).
_ = posix_spawn_file_actions_adddup2(fileActions, fd, fd)
// posix_spawn_file_actions_adddup2() will automatically clear
// FD_CLOEXEC after forking but before execing even if the old and new
// file descriptors are equal. This behavior is supported by
// Glibc ≥ 2.29, FreeBSD, OpenBSD, and Android (Bionic) and is
// standardized in POSIX.1-2024 (see https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_adddup2.html
// and https://www.austingroupbugs.net/view.php?id=411).
_ = posix_spawn_file_actions_adddup2(fileActions, fd, fd)
#if canImport(Glibc) && !os(FreeBSD) && !os(OpenBSD)
if _slowPath(glibcVersion.major < 2 || (glibcVersion.major == 2 && glibcVersion.minor < 29)) {
// This system is using an older version of glibc that does not
// implement FD_CLOEXEC clearing in posix_spawn_file_actions_adddup2(),
// so we must clear it here in the parent process.
try setFD_CLOEXEC(false, onFileDescriptor: fd)
}
if _slowPath(glibcVersion.major < 2 || (glibcVersion.major == 2 && glibcVersion.minor < 29)) {
// This system is using an older version of glibc that does not
// implement FD_CLOEXEC clearing in posix_spawn_file_actions_adddup2(),
// so we must clear it here in the parent process.
try setFD_CLOEXEC(false, onFileDescriptor: fd)
}
#endif
#endif
highestFD = max(highestFD, fd)
}
highestFD = max(highestFD, fd)
}
}
func inherit(_ fileHandle: borrowing FileHandle?, as standardFD: CInt? = nil) throws {
Expand Down Expand Up @@ -231,20 +229,19 @@ func spawnExecutable(
}
#elseif os(Windows)
return try _withStartupInfoEx(attributeCount: 1) { startupInfo in
@_lifetime(fileHandle)
func inherit(_ fileHandle: borrowing FileHandle) throws -> HANDLE? {
try fileHandle.withUnsafeWindowsHANDLE { windowsHANDLE in
guard let windowsHANDLE else {
throw SystemError(description: "A child process cannot inherit a file handle without an associated Windows handle. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new")
}

// Ensure the file handle can be inherited by the child process.
guard SetHandleInformation(windowsHANDLE, DWORD(HANDLE_FLAG_INHERIT), DWORD(HANDLE_FLAG_INHERIT)) else {
throw Win32Error(rawValue: GetLastError())
}

return windowsHANDLE
guard let windowsHANDLE = fileHandle.unsafeWindowsHANDLE else {
throw SystemError(description: "A child process cannot inherit a file handle without an associated Windows handle. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new")
}
// Ensure the file handle can be inherited by the child process.
guard SetHandleInformation(windowsHANDLE, DWORD(HANDLE_FLAG_INHERIT), DWORD(HANDLE_FLAG_INHERIT)) else {
throw Win32Error(rawValue: GetLastError())
}

return windowsHANDLE
}
@_lifetime(fileHandle)
func inherit(_ fileHandle: borrowing FileHandle?) throws -> HANDLE? {
if fileHandle != nil {
return try inherit(fileHandle!)
Expand Down
Loading