diff --git a/FlyingSocks/Sources/Socket+Darwin.swift b/FlyingSocks/Sources/Socket+Darwin.swift index c36f674..2524411 100644 --- a/FlyingSocks/Sources/Socket+Darwin.swift +++ b/FlyingSocks/Sources/Socket+Darwin.swift @@ -89,12 +89,15 @@ extension Socket { static func makeAddressUnix(path: String) -> Darwin.sockaddr_un { var addr = Darwin.sockaddr_un() addr.sun_family = sa_family_t(AF_UNIX) - let pathCount = min(path.utf8.count, 104) + // Darwin declares `char sun_path[104]`; reserve the last byte + // for the NUL terminator that String(cString:) and unlink() read back. + let pathCount = min(path.utf8.count, 103) let len = UInt8(MemoryLayout.size + MemoryLayout.size + pathCount + 1) - _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in + withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in path.withCString { - strncpy(ptr, $0, Int(len)) + _ = strncpy(ptr, $0, pathCount) } + ptr[pathCount] = 0 } addr.sun_len = len return addr diff --git a/FlyingSocks/Tests/SocketAddressTests.swift b/FlyingSocks/Tests/SocketAddressTests.swift index 995ad74..9108199 100644 --- a/FlyingSocks/Tests/SocketAddressTests.swift +++ b/FlyingSocks/Tests/SocketAddressTests.swift @@ -148,6 +148,30 @@ struct SocketAddressTests { ) } + #if canImport(Darwin) + @Test + func unixMaxLengthPath_IsCorrectlyDecodedFromStorage() throws { + let path = "/tmp/" + String(repeating: "x", count: 98) + let addr = sockaddr_un.unix(path: path) + + #expect(Int(addr.sun_len) <= MemoryLayout.size) + #expect( + try Socket.makeAddress(from: addr.makeStorage()) == .unix(path) + ) + } + + @Test + func unixOverlongPath_TruncatesWithoutOverflow() throws { + let path = "/tmp/" + String(repeating: "x", count: 99) + let addr = sockaddr_un.unix(path: path) + + #expect(Int(addr.sun_len) <= MemoryLayout.size) + #expect( + try Socket.makeAddress(from: addr.makeStorage()) == .unix(String(path.prefix(103))) + ) + } + #endif + #if canImport(Glibc) || canImport(Musl) || canImport(Android) @Test func unixAbstractNamespace_IsCorrectlyDecodedFromStorage() throws { @@ -268,7 +292,7 @@ struct SocketAddressTests { func maximumPathLengthForUnixDomainSocket() { var addrUn = sockaddr_un() addrUn.sun_family = sa_family_t(AF_UNIX) - let maxPathLength = MemoryLayout.size - MemoryLayout.size - 1 + let maxPathLength = MemoryLayout.size(ofValue: addrUn.sun_path) - 1 let maxPath = String(repeating: "a", count: maxPathLength) _ = maxPath.withCString { pathPtr in memcpy(&addrUn.sun_path, pathPtr, maxPath.count + 1)