From af4544c86920634166223e4e3f6fe99db9e2dcaf Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 9 Jun 2023 17:56:36 -0700 Subject: [PATCH 01/18] Re-enable Mach.Port --- Sources/System/MachPort.swift | 2 +- Tests/SystemTests/MachPortTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 04d2cc5b..f1d29b7e 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -7,7 +7,7 @@ See https://swift.org/LICENSE.txt for license information */ -#if false && swift(>=5.8) && $MoveOnly && (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) +#if swift(>=5.9) && (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) import Darwin.Mach diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 31a654cb..01855e34 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -7,7 +7,7 @@ See https://swift.org/LICENSE.txt for license information */ -#if false && swift(>=5.8) && $MoveOnly && (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) +#if swift(>=5.9) && (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) import XCTest import Darwin.Mach From 2df5b0b0315456a816bff29570fb160b6500b083 Mon Sep 17 00:00:00 2001 From: Daniel Loffgren Date: Tue, 8 Aug 2023 17:36:20 -0700 Subject: [PATCH 02/18] srdelta argument to mach_port_destruct should be zero This should never have been -1, as there is no send right for it to balance when `RightType.self == ReceiveRight.self`. --- Sources/System/MachPort.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index f1d29b7e..b1b2f1c1 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -86,7 +86,7 @@ public enum Mach { _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_DEAD_NAME, -1)) } else { if RightType.self == ReceiveRight.self { - _machPrecondition(mach_port_destruct(mach_task_self_, _name, -1, _context)) + _machPrecondition(mach_port_destruct(mach_task_self_, _name, 0, _context)) } else if RightType.self == SendRight.self { _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_SEND, -1)) } else if RightType.self == SendOnceRight.self { From bf16d3da30634886b7730b90d495b8f2c1fb022f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 13:16:40 -0700 Subject: [PATCH 03/18] [test] use `XCTAssertEqual` or `XCTAssertNotEqual` --- Tests/SystemTests/MachPortTests.swift | 43 +++++++++++++-------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 01855e34..cf68cd6d 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -23,7 +23,7 @@ final class MachPortTests: XCTestCase { var refCount:mach_port_urefs_t = 0 withUnsafeMutablePointer(to: &refCount) { refCount in let kr = mach_port_get_refs(mach_task_self_, name, kind, refCount) - assert(kr == KERN_SUCCESS) + XCTAssertEqual(kr, KERN_SUCCESS) } return refCount } @@ -33,20 +33,20 @@ final class MachPortTests: XCTestCase { return refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_RECEIVE) } - func testRecieveRightDeallocation() throws { + func testReceiveRightDeallocation() throws { var name:mach_port_name_t = 0 // Never read withUnsafeMutablePointer(to:&name) { name in let kr = mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, name) - assert(kr == KERN_SUCCESS) + XCTAssertEqual(kr, KERN_SUCCESS) } - XCTAssert(name != 0xFFFFFFFF) + XCTAssertNotEqual(name, 0xFFFFFFFF) let one = scopedReceiveRight(name:name) let zero = refCountForMachPortName(name:name, kind: MACH_PORT_RIGHT_RECEIVE) - XCTAssert(one == 1); - XCTAssert(zero == 0); + XCTAssertEqual(one, 1); + XCTAssertEqual(zero, 0); } func consumeSendRightAutomatically(name:mach_port_name_t) -> mach_port_urefs_t { @@ -61,11 +61,11 @@ final class MachPortTests: XCTestCase { let recv = Mach.Port() recv.withBorrowedName { name in let kr = mach_port_insert_right(mach_task_self_, name, name, mach_msg_type_name_t(MACH_MSG_TYPE_MAKE_SEND)) - XCTAssert(kr == KERN_SUCCESS) + XCTAssertEqual(kr, KERN_SUCCESS) let one = consumeSendRightAutomatically(name:name) - XCTAssert(one == 1); + XCTAssertEqual(one, 1); let zero = refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_SEND) - XCTAssert(zero == 0); + XCTAssertEqual(zero, 0); } } @@ -77,29 +77,29 @@ final class MachPortTests: XCTestCase { let one = send.withBorrowedName { name in return self.refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_SEND) } - XCTAssert(one == 1) + XCTAssertEqual(one, 1) return send.relinquish() })() let stillOne = refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_SEND) - XCTAssert(stillOne == 1) + XCTAssertEqual(stillOne, 1) } func testMakeSendCountSettable() throws { var recv = Mach.Port() - XCTAssert(recv.makeSendCount == 0) + XCTAssertEqual(recv.makeSendCount, 0) recv.makeSendCount = 7 - XCTAssert(recv.makeSendCount == 7) + XCTAssertEqual(recv.makeSendCount, 7) } func makeSendRight() throws -> Mach.Port { let recv = Mach.Port() let zero = recv.makeSendCount - XCTAssert(zero == 0) + XCTAssertEqual(zero, 0) let send = recv.makeSendRight() let one = recv.makeSendCount - XCTAssert(one == 1) + XCTAssertEqual(one, 1) return send } @@ -110,10 +110,10 @@ final class MachPortTests: XCTestCase { func testMakeSendOnceDoesntIncrementMakeSendCount() throws { let recv = Mach.Port() let zero = recv.makeSendCount - XCTAssert(zero == 0) + XCTAssertEqual(zero, 0) _ = recv.makeSendOnceRight() let same = recv.makeSendCount - XCTAssert(same == zero) + XCTAssertEqual(same, zero) } func testMakeSendOnceIsUnique() throws { @@ -121,8 +121,7 @@ final class MachPortTests: XCTestCase { let once = recv.makeSendOnceRight() recv.withBorrowedName { rname in once.withBorrowedName { oname in - print(oname, rname) - XCTAssert(oname != rname) + XCTAssertNotEqual(oname, rname) } } } @@ -130,13 +129,13 @@ final class MachPortTests: XCTestCase { func testCopySend() throws { let recv = Mach.Port() let zero = recv.makeSendCount - XCTAssert(zero == 0) + XCTAssertEqual(zero, 0) let send = recv.makeSendRight() let one = recv.makeSendCount - XCTAssert(one == 1) + XCTAssertEqual(one, 1) _ = try send.copySendRight() let same = recv.makeSendCount - XCTAssert(same == one) + XCTAssertEqual(same, one) } } From 9123120c08ec18e525d488080478c5c62b40099c Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 13:17:37 -0700 Subject: [PATCH 04/18] destroy Send rights with `mach_port_deallocate` --- Sources/System/MachPort.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index b1b2f1c1..96dd9929 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -88,7 +88,7 @@ public enum Mach { if RightType.self == ReceiveRight.self { _machPrecondition(mach_port_destruct(mach_task_self_, _name, 0, _context)) } else if RightType.self == SendRight.self { - _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_SEND, -1)) + _machPrecondition(mach_port_deallocate(mach_task_self_, _name)) } else if RightType.self == SendOnceRight.self { _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_SEND_ONCE, -1)) } From 669dcf2c25f7f1c63612e55dc478f8837a50409a Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 13:48:55 -0700 Subject: [PATCH 05/18] ensure Mach.Port lives until the function returns --- Tests/SystemTests/MachPortTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index cf68cd6d..299809cd 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -29,7 +29,8 @@ final class MachPortTests: XCTestCase { } func scopedReceiveRight(name:mach_port_name_t) -> mach_port_urefs_t { - _ = Mach.Port(name:name) // this should automatically deallocate when going out of scope + let right = Mach.Port(name:name) // this should automatically deallocate when going out of scope + defer { _ = right } return refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_RECEIVE) } From 0539daa364e2c006e1349369c2c4f7a164126933 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 14:17:43 -0700 Subject: [PATCH 06/18] fix test of receive-right deallocation --- Tests/SystemTests/MachPortTests.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 299809cd..41e28f60 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -23,7 +23,11 @@ final class MachPortTests: XCTestCase { var refCount:mach_port_urefs_t = 0 withUnsafeMutablePointer(to: &refCount) { refCount in let kr = mach_port_get_refs(mach_task_self_, name, kind, refCount) - XCTAssertEqual(kr, KERN_SUCCESS) + if kr == KERN_INVALID_NAME { + refCount.pointee = 0 + } else { + XCTAssertEqual(kr, KERN_SUCCESS) + } } return refCount } @@ -43,11 +47,14 @@ final class MachPortTests: XCTestCase { XCTAssertNotEqual(name, 0xFFFFFFFF) - let one = scopedReceiveRight(name:name) - let zero = refCountForMachPortName(name:name, kind: MACH_PORT_RIGHT_RECEIVE) + let originalCount = refCountForMachPortName(name: name, kind: MACH_PORT_RIGHT_RECEIVE) + XCTAssertEqual(originalCount, 1) + + let incrementedCount = scopedReceiveRight(name:name) + XCTAssertEqual(incrementedCount, 1); - XCTAssertEqual(one, 1); - XCTAssertEqual(zero, 0); + let deallocated = refCountForMachPortName(name:name, kind: MACH_PORT_RIGHT_RECEIVE) + XCTAssertEqual(deallocated, 0); } func consumeSendRightAutomatically(name:mach_port_name_t) -> mach_port_urefs_t { From 6ee96ffdb5a1645cb6755367f86bb87c2e9bf996 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 14:52:35 -0700 Subject: [PATCH 07/18] modify consuming methods to call `discard self` --- Sources/System/MachPort.swift | 26 +++++++++++++++++--------- Tests/SystemTests/MachPortTests.swift | 5 +++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 96dd9929..1ae99bf8 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -167,9 +167,11 @@ extension Mach.Port where RightType == Mach.ReceiveRight { /// After this function completes, the Mach.Port is destroyed and no longer /// usable. @inlinable - public __consuming func relinquish( + public consuming func relinquish( ) -> (name: mach_port_name_t, context: mach_port_context_t) { - return (name: _name, context: _context) + let destructured = (name: _name, context: _context) + discard self + return destructured } /// Remove guard and transfer ownership of the underlying port right to @@ -187,9 +189,11 @@ extension Mach.Port where RightType == Mach.ReceiveRight { /// Mach.ReceiveRights. Use relinquish() to avoid the syscall and extract /// the context value along with the port name. @inlinable - public __consuming func unguardAndRelinquish() -> mach_port_name_t { - _machPrecondition(mach_port_unguard(mach_task_self_, _name, _context)) - return _name + public consuming func unguardAndRelinquish() -> mach_port_name_t { + let (name, context) = (_name, _context) + discard self + _machPrecondition(mach_port_unguard(mach_task_self_, name, context)) + return name } /// Borrow access to the port name in a block that can perform @@ -288,8 +292,10 @@ extension Mach.Port where RightType == Mach.SendRight { /// After this function completes, the Mach.Port is destroyed and no longer /// usable. @inlinable - public __consuming func relinquish() -> mach_port_name_t { - return _name + public consuming func relinquish() -> mach_port_name_t { + let name = _name + discard self + return name } /// Create another send right from a given send right. @@ -326,8 +332,10 @@ extension Mach.Port where RightType == Mach.SendOnceRight { /// After this function completes, the Mach.Port is destroyed and no longer /// usable. @inlinable - public __consuming func relinquish() -> mach_port_name_t { - return _name + public consuming func relinquish() -> mach_port_name_t { + let name = _name + discard self + return name } } diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 41e28f60..76037615 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -92,6 +92,11 @@ final class MachPortTests: XCTestCase { let stillOne = refCountForMachPortName(name:name, kind:MACH_PORT_RIGHT_SEND) XCTAssertEqual(stillOne, 1) + + recv.withBorrowedName { + let alsoOne = refCountForMachPortName(name: $0, kind: MACH_PORT_RIGHT_RECEIVE) + XCTAssertEqual(alsoOne, 1) + } } func testMakeSendCountSettable() throws { From e8bb779909f33f0df50ae8c08700409883c9bc44 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 15:24:03 -0700 Subject: [PATCH 08/18] use inout conversion - this is the situation where it is appropriate --- Sources/System/MachPort.swift | 26 ++++++++++++-------------- Tests/SystemTests/MachPortTests.swift | 22 +++++++++------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 1ae99bf8..0f8b8a44 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -147,9 +147,9 @@ extension Mach.Port where RightType == Mach.ReceiveRight { @inlinable public init() { var storage: mach_port_name_t = mach_port_name_t(MACH_PORT_NULL) - withUnsafeMutablePointer(to: &storage) { storage in - _machPrecondition(mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, storage)) - } + _machPrecondition( + mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &storage) + ) // name-only init will guard ReceiveRights self.init(name: storage) @@ -224,17 +224,15 @@ extension Mach.Port where RightType == Mach.ReceiveRight { var newRight: mach_port_name_t = mach_port_name_t(MACH_PORT_NULL) var newRightType: mach_port_type_t = MACH_PORT_TYPE_NONE - withUnsafeMutablePointer(to: &newRight) { newRight in - withUnsafeMutablePointer(to: &newRightType) { newRightType in - _machPrecondition( - mach_port_extract_right(mach_task_self_, - _name, - mach_msg_type_name_t(MACH_MSG_TYPE_MAKE_SEND_ONCE), - newRight, - newRightType) - ) - } - } + _machPrecondition( + mach_port_extract_right( + mach_task_self_, + _name, + mach_msg_type_name_t(MACH_MSG_TYPE_MAKE_SEND_ONCE), + &newRight, + &newRightType + ) + ) // The value of newRight is validated by the Mach.Port initializer precondition(newRightType == MACH_MSG_TYPE_MOVE_SEND_ONCE) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 76037615..74ea55a0 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -20,14 +20,12 @@ import System final class MachPortTests: XCTestCase { func refCountForMachPortName(name:mach_port_name_t, kind:mach_port_right_t) -> mach_port_urefs_t { - var refCount:mach_port_urefs_t = 0 - withUnsafeMutablePointer(to: &refCount) { refCount in - let kr = mach_port_get_refs(mach_task_self_, name, kind, refCount) - if kr == KERN_INVALID_NAME { - refCount.pointee = 0 - } else { - XCTAssertEqual(kr, KERN_SUCCESS) - } + var refCount:mach_port_urefs_t = .max + let kr = mach_port_get_refs(mach_task_self_, name, kind, &refCount) + if kr == KERN_INVALID_NAME { + refCount = 0 + } else { + XCTAssertEqual(kr, KERN_SUCCESS) } return refCount } @@ -39,11 +37,9 @@ final class MachPortTests: XCTestCase { } func testReceiveRightDeallocation() throws { - var name:mach_port_name_t = 0 // Never read - withUnsafeMutablePointer(to:&name) { name in - let kr = mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, name) - XCTAssertEqual(kr, KERN_SUCCESS) - } + var name: mach_port_name_t = 0xFFFFFFFF + let kr = mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &name) + XCTAssertEqual(kr, KERN_SUCCESS) XCTAssertNotEqual(name, 0xFFFFFFFF) From 40b5b3068b57e211a6245bcf599152d80ddfb4ca Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 16:18:06 -0700 Subject: [PATCH 09/18] test all the `relinquish()` methods --- Sources/System/MachPort.swift | 3 +-- Tests/SystemTests/MachPortTests.swift | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 0f8b8a44..7fd98bf9 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -190,8 +190,7 @@ extension Mach.Port where RightType == Mach.ReceiveRight { /// the context value along with the port name. @inlinable public consuming func unguardAndRelinquish() -> mach_port_name_t { - let (name, context) = (_name, _context) - discard self + let (name, context) = self.relinquish() _machPrecondition(mach_port_unguard(mach_task_self_, name, context)) return name } diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 74ea55a0..7c80f0de 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -95,6 +95,42 @@ final class MachPortTests: XCTestCase { } } + func testSendOnceRightRelinquishment() throws { + let recv = Mach.Port() + + let name = ({ + let send = recv.makeSendOnceRight() + let one = send.withBorrowedName { name in + return self.refCountForMachPortName(name: name, kind: MACH_PORT_RIGHT_SEND_ONCE) + } + XCTAssertEqual(one, 1) + + return send.relinquish() + })() + + let stillOne = refCountForMachPortName(name: name, kind: MACH_PORT_RIGHT_SEND_ONCE) + XCTAssertEqual(stillOne, 1) + + recv.withBorrowedName { + let alsoOne = refCountForMachPortName(name: $0, kind: MACH_PORT_RIGHT_RECEIVE) + XCTAssertEqual(alsoOne, 1) + } + } + + func testReceiveRightRelinquishment() throws { + let recv = Mach.Port() + + let one = recv.withBorrowedName { + self.refCountForMachPortName(name: $0, kind: MACH_PORT_RIGHT_RECEIVE) + } + XCTAssertEqual(one, 1) + + let name = recv.unguardAndRelinquish() + + let stillOne = refCountForMachPortName(name: name, kind: MACH_PORT_RIGHT_RECEIVE) + XCTAssertEqual(stillOne, 1) + } + func testMakeSendCountSettable() throws { var recv = Mach.Port() XCTAssertEqual(recv.makeSendCount, 0) From 5e03246e4eddb9836de18d114405b70cef44f584 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 17:24:49 -0700 Subject: [PATCH 10/18] test copies of dead mach port names --- Sources/System/MachPort.swift | 2 +- Tests/SystemTests/MachPortTests.swift | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 7fd98bf9..9867ed89 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -308,7 +308,7 @@ extension Mach.Port where RightType == Mach.SendRight { // name is the same because send rights are coalesced let kr = mach_port_insert_right(mach_task_self_, _name, _name, mach_msg_type_name_t(how)) - if kr == KERN_INVALID_CAPABILITY { + if kr == KERN_INVALID_NAME { throw Mach.PortRightError.deadName } _machPrecondition(kr) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 7c80f0de..95d2f638 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -183,6 +183,17 @@ final class MachPortTests: XCTestCase { XCTAssertEqual(same, one) } + + func testCopyDeadName() throws { + let send = Mach.Port(name: 0xffffffff) + do { + let copy = try send.copySendRight() + _ = copy + } + catch Mach.PortRightError.deadName { + _ = send.relinquish() + } + } } #endif From d259ef476e1fffa2913c979eef98320eefd5eb56 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 17:51:54 -0700 Subject: [PATCH 11/18] test two-parameter `withBorrowedName` --- Sources/System/MachPort.swift | 1 + Tests/SystemTests/MachPortTests.swift | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 9867ed89..a67a01a3 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -135,6 +135,7 @@ extension Mach.Port where RightType == Mach.ReceiveRight { /// The underlying port right will be automatically deallocated when /// the Mach.Port object is destroyed. public init(name: mach_port_name_t, context: mach_port_context_t) { + precondition(name != mach_port_name_t(MACH_PORT_NULL), "Mach.Port cannot be initialized with MACH_PORT_NULL") self._name = name self._context = context } diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 95d2f638..bf1e118c 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -194,6 +194,22 @@ final class MachPortTests: XCTestCase { _ = send.relinquish() } } + + func testMakeReceivedRightFromExistingName() throws { + var name = mach_port_name_t(MACH_PORT_NULL) + var kr = mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &name) + XCTAssertEqual(kr, KERN_SUCCESS) + XCTAssertNotEqual(name, mach_port_name_t(MACH_PORT_NULL)) + let context = mach_port_context_t(arc4random()) + kr = mach_port_guard(mach_task_self_, name, context, 0) + XCTAssertEqual(kr, KERN_SUCCESS) + + let right = Mach.Port(name: name, context: context) + right.withBorrowedName { + XCTAssertEqual(name, $0) + XCTAssertEqual(context, $1) + } + } } #endif From e4d06ae3ea97ecc35311699e1895f61932e35499 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Aug 2023 17:52:50 -0700 Subject: [PATCH 12/18] simplify deinit --- Sources/System/MachPort.swift | 20 ++++++++++---------- Tests/SystemTests/MachPortTests.swift | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index a67a01a3..4ca3572e 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -81,17 +81,17 @@ public enum Mach { } deinit { - if _name == 0xFFFFFFFF /* MACH_PORT_DEAD */ { - precondition(RightType.self != ReceiveRight.self, "Receive rights cannot be dead names") - _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_DEAD_NAME, -1)) + if RightType.self == ReceiveRight.self { + precondition(_name != 0xffffffff, "Receive rights cannot be dead names") + _machPrecondition( + mach_port_destruct(mach_task_self_, _name, 0, _context) + ) } else { - if RightType.self == ReceiveRight.self { - _machPrecondition(mach_port_destruct(mach_task_self_, _name, 0, _context)) - } else if RightType.self == SendRight.self { - _machPrecondition(mach_port_deallocate(mach_task_self_, _name)) - } else if RightType.self == SendOnceRight.self { - _machPrecondition(mach_port_mod_refs(mach_task_self_, _name, MACH_PORT_RIGHT_SEND_ONCE, -1)) - } + assert( + RightType.self == SendRight.self || + RightType.self == SendOnceRight.self + ) + _machPrecondition(mach_port_deallocate(mach_task_self_, _name)) } } } diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index bf1e118c..3c64ce88 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -210,6 +210,20 @@ final class MachPortTests: XCTestCase { XCTAssertEqual(context, $1) } } + + func testDeinitDeadSendRight() throws { + let send = Mach.Port(name: 0xffffffff) + send.withBorrowedName { + XCTAssertEqual($0, .max) + } + _ = consume send + + let send1 = Mach.Port(name: 0xffffffff) + send1.withBorrowedName { + XCTAssertEqual($0, .max) + } + _ = consume send1 + } } #endif From 6189c1f553ea30bc64a59f27cc851d7daae03269 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 11 Aug 2023 14:09:44 -0700 Subject: [PATCH 13/18] fix `copySendRight()` for send rights that become dead names --- Sources/System/MachPort.swift | 2 +- Tests/SystemTests/MachPortTests.swift | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 4ca3572e..0f58243a 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -309,7 +309,7 @@ extension Mach.Port where RightType == Mach.SendRight { // name is the same because send rights are coalesced let kr = mach_port_insert_right(mach_task_self_, _name, _name, mach_msg_type_name_t(how)) - if kr == KERN_INVALID_NAME { + if kr == KERN_INVALID_NAME || kr == KERN_INVALID_CAPABILITY { throw Mach.PortRightError.deadName } _machPrecondition(kr) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 3c64ce88..082653e5 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -185,13 +185,24 @@ final class MachPortTests: XCTestCase { } func testCopyDeadName() throws { + let recv = Mach.Port() + let send = recv.makeSendRight() + _ = consume recv // and turn `send` into a dead name + do { + let copy = try send.copySendRight() + _ = copy + } + catch Mach.PortRightError.deadName { + } + } + + func testCopyDeadName2() throws { let send = Mach.Port(name: 0xffffffff) do { let copy = try send.copySendRight() _ = copy } catch Mach.PortRightError.deadName { - _ = send.relinquish() } } From f5edd720bd7418cda0f4ee29e779eac74705e025 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 11 Aug 2023 18:03:24 -0700 Subject: [PATCH 14/18] clarify some tests --- Tests/SystemTests/MachPortTests.swift | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 082653e5..07da8bb2 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -193,6 +193,7 @@ final class MachPortTests: XCTestCase { _ = copy } catch Mach.PortRightError.deadName { + // success } } @@ -203,10 +204,11 @@ final class MachPortTests: XCTestCase { _ = copy } catch Mach.PortRightError.deadName { + // success } } - func testMakeReceivedRightFromExistingName() throws { + func testMakeReceiveRightFromExistingName() throws { var name = mach_port_name_t(MACH_PORT_NULL) var kr = mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &name) XCTAssertEqual(kr, KERN_SUCCESS) @@ -222,17 +224,14 @@ final class MachPortTests: XCTestCase { } } - func testDeinitDeadSendRight() throws { - let send = Mach.Port(name: 0xffffffff) - send.withBorrowedName { - XCTAssertEqual($0, .max) - } - _ = consume send + func testDeinitDeadSendRights() throws { + let recv = Mach.Port() + let send = recv.makeSendRight() + let send1 = recv.makeSendOnceRight() - let send1 = Mach.Port(name: 0xffffffff) - send1.withBorrowedName { - XCTAssertEqual($0, .max) - } + _ = consume recv + // `send` and `send1` have become dead names + _ = consume send _ = consume send1 } } From 65693b8b808d013cab03055963989cbe97a145ba Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 14 Aug 2023 18:00:14 -0700 Subject: [PATCH 15/18] improve memory rebinding for `mach_port_get_attributes` call --- Sources/System/MachPort.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 0f58243a..58521469 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -263,11 +263,19 @@ extension Mach.Port where RightType == Mach.ReceiveRight { public var makeSendCount: mach_port_mscount_t { get { var status: mach_port_status = mach_port_status() - var size: mach_msg_type_number_t = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size) - withUnsafeMutablePointer(to: &size) { size in - withUnsafeMutablePointer(to: &status) { status in - let info = UnsafeMutableRawPointer(status).bindMemory(to: integer_t.self, capacity: 1) - _machPrecondition(mach_port_get_attributes(mach_task_self_, _name, MACH_PORT_RECEIVE_STATUS, info, size)) + var size = mach_msg_type_number_t( + MemoryLayout.size / MemoryLayout.size + ) + + withUnsafeMutablePointer(to: &status) { + let status = UnsafeMutableBufferPointer(start: $0, count: 1) + status.withMemoryRebound(to: integer_t.self) { + let info = $0.baseAddress + _machPrecondition( + mach_port_get_attributes( + mach_task_self_, _name, MACH_PORT_RECEIVE_STATUS, info, &size + ) + ) } } return status.mps_mscount From 8730f2cf256694ae5cee761e2f687df064f0a480 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 15 Aug 2023 09:14:21 -0700 Subject: [PATCH 16/18] [gardening] 80-column enforcement --- Sources/System/MachPort.swift | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Sources/System/MachPort.swift b/Sources/System/MachPort.swift index 58521469..223757b8 100644 --- a/Sources/System/MachPort.swift +++ b/Sources/System/MachPort.swift @@ -48,11 +48,13 @@ public enum Mach { /// /// This initializer makes a syscall to guard the right. public init(name: mach_port_name_t) { - precondition(name != mach_port_name_t(MACH_PORT_NULL), "Mach.Port cannot be initialized with MACH_PORT_NULL") + precondition(name != mach_port_name_t(MACH_PORT_NULL), + "Mach.Port cannot be initialized with MACH_PORT_NULL") self._name = name if RightType.self == ReceiveRight.self { - precondition(name != 0xFFFFFFFF /* MACH_PORT_DEAD */, "Receive rights cannot be dead names") + precondition(name != 0xFFFFFFFF /* MACH_PORT_DEAD */, + "Receive rights cannot be dead names") let secret = mach_port_context_t(arc4random()) _machPrecondition(mach_port_guard(mach_task_self_, name, secret, 0)) @@ -82,7 +84,8 @@ public enum Mach { deinit { if RightType.self == ReceiveRight.self { - precondition(_name != 0xffffffff, "Receive rights cannot be dead names") + precondition(_name != 0xFFFFFFFF /* MACH_PORT_DEAD */, + "Receive rights cannot be dead names") _machPrecondition( mach_port_destruct(mach_task_self_, _name, 0, _context) ) @@ -135,7 +138,8 @@ extension Mach.Port where RightType == Mach.ReceiveRight { /// The underlying port right will be automatically deallocated when /// the Mach.Port object is destroyed. public init(name: mach_port_name_t, context: mach_port_context_t) { - precondition(name != mach_port_name_t(MACH_PORT_NULL), "Mach.Port cannot be initialized with MACH_PORT_NULL") + precondition(name != mach_port_name_t(MACH_PORT_NULL), + "Mach.Port cannot be initialized with MACH_PORT_NULL") self._name = name self._context = context } @@ -251,7 +255,11 @@ extension Mach.Port where RightType == Mach.ReceiveRight { let how = MACH_MSG_TYPE_MAKE_SEND // name is the same because send and recv rights are coalesced - _machPrecondition(mach_port_insert_right(mach_task_self_, _name, _name, mach_msg_type_name_t(how))) + _machPrecondition( + mach_port_insert_right( + mach_task_self_, _name, _name, mach_msg_type_name_t(how) + ) + ) return Mach.Port(name: _name) } @@ -316,7 +324,9 @@ extension Mach.Port where RightType == Mach.SendRight { let how = MACH_MSG_TYPE_COPY_SEND // name is the same because send rights are coalesced - let kr = mach_port_insert_right(mach_task_self_, _name, _name, mach_msg_type_name_t(how)) + let kr = mach_port_insert_right( + mach_task_self_, _name, _name, mach_msg_type_name_t(how) + ) if kr == KERN_INVALID_NAME || kr == KERN_INVALID_CAPABILITY { throw Mach.PortRightError.deadName } From faffb9a15a84f5194085d4c853f42651b683e5d0 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 16 Aug 2023 13:19:52 -0700 Subject: [PATCH 17/18] Apply suggestions from code review This better communicates the intention. Co-authored-by: loffgren <117697138+loffgren@users.noreply.github.com> --- Tests/SystemTests/MachPortTests.swift | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 07da8bb2..8a6ade6a 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -188,23 +188,15 @@ final class MachPortTests: XCTestCase { let recv = Mach.Port() let send = recv.makeSendRight() _ = consume recv // and turn `send` into a dead name - do { - let copy = try send.copySendRight() - _ = copy - } - catch Mach.PortRightError.deadName { - // success + XCTAssertThrowsError(try send.copySendRight(), "Copying a dead name should throw") { error in + XCTAssertEqual(error, Mach.PortRightError.deadName) } } func testCopyDeadName2() throws { let send = Mach.Port(name: 0xffffffff) - do { - let copy = try send.copySendRight() - _ = copy - } - catch Mach.PortRightError.deadName { - // success + XCTAssertThrowsError(try send.copySendRight(), "Copying a dead name should throw") { error in + XCTAssertEqual(error, Mach.PortRightError.deadName) } } From ad407249fec4293dbf8b2578ac54b65f98060313 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 16 Aug 2023 13:34:41 -0700 Subject: [PATCH 18/18] make test expression return `Void` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - It can’t return `Mach.Port`, because a noncopyable type cannot currently be a generic type argument. --- Tests/SystemTests/MachPortTests.swift | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Tests/SystemTests/MachPortTests.swift b/Tests/SystemTests/MachPortTests.swift index 8a6ade6a..07b74106 100644 --- a/Tests/SystemTests/MachPortTests.swift +++ b/Tests/SystemTests/MachPortTests.swift @@ -188,15 +188,25 @@ final class MachPortTests: XCTestCase { let recv = Mach.Port() let send = recv.makeSendRight() _ = consume recv // and turn `send` into a dead name - XCTAssertThrowsError(try send.copySendRight(), "Copying a dead name should throw") { error in - XCTAssertEqual(error, Mach.PortRightError.deadName) + XCTAssertThrowsError( + _ = try send.copySendRight(), + "Copying a dead name should throw" + ) { error in + XCTAssertEqual( + error as! Mach.PortRightError, Mach.PortRightError.deadName + ) } } func testCopyDeadName2() throws { let send = Mach.Port(name: 0xffffffff) - XCTAssertThrowsError(try send.copySendRight(), "Copying a dead name should throw") { error in - XCTAssertEqual(error, Mach.PortRightError.deadName) + XCTAssertThrowsError( + _ = try send.copySendRight(), + "Copying a dead name should throw" + ) { error in + XCTAssertEqual( + error as! Mach.PortRightError, Mach.PortRightError.deadName + ) } }