Swift getaddrinfo

时间:2016-10-04 16:28:23

标签: swift memory posix low-level-api

POSIX def test(path, gradient_magnitude=1.): im = Image.open(path) if im.mode != 'RGBA': im = im.convert('RGBA') width, height = im.size gradient = Image.new('L', (width, 1), color=0xFF) for x in range(width): # gradient.putpixel((x, 0), 255-x) gradient.putpixel((x, 0), int(255 * (1 - gradient_magnitude * float(x)/width))) alpha = gradient.resize(im.size) black_im = Image.new('RGBA', (width, height), color=0) # i.e. black black_im.putalpha(alpha) gradient_im = Image.alpha_composite(im, black_im) gradient_im.save('out.png', 'PNG') 分配以后必须使用getaddrinfo释放的内存。 见http://manpages.ubuntu.com/manpages/xenial/en/man3/getaddrinfo.3.html

为了简化API,我创建了这个功能:

freeaddrinfo
但是,我并不觉得这个功能是正确的。

  • Swift内存模型如何知道import Foundation enum SystemError: Swift.Error { case getaddrinfo(Int32, Int32?) } public func getaddrinfo(node: String?, service: String?, hints: addrinfo?) throws -> [addrinfo] { var err: Int32 var res: UnsafeMutablePointer<addrinfo>? if var hints = hints { err = getaddrinfo(node, service, &hints, &res) } else { err = getaddrinfo(node, service, nil, &res) } if err == EAI_SYSTEM { throw SystemError.getaddrinfo(err, errno) } if err != 0 { throw SystemError.getaddrinfo(err, nil) } defer { freeaddrinfo(res) } var result = [addrinfo]() var ai = res?.pointee while ai != nil { result.append(ai!) ai = ai!.ai_next?.pointee } return result } 分配内存,Swift不应该用自己的东西覆盖那个内存?
  • Swift如何知道getaddrinfo删除整个列表,并且它应该复制已分配给结果数组的ai信息?

freeaddrinfo接口的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

getaddrinfo分配的内存(例如malloc)将不会被授予任何其他内存 动态内存分配功能在同一个运行过程中 直到freeaddrinfo发布(例如free)。 因此,Swift运行时不会践踏该内存(如果我们这样做) 假设它没有编程错误,例如错误的指针计算。)

同样struct addrinfo是值类型,所以

result.append(ai!)

会将指向结构的副本附加到数组中。

但仍有问题。 struct addrinfo的部分成员 是指针

public var ai_canonname: UnsafeMutablePointer<Int8>! /* canonical name for hostname */
public var ai_addr: UnsafeMutablePointer<sockaddr>! /* binary address */

可能指向由getaddrinfo分配的内存,因此 在freeaddrinfo之后无效,并在您之后取消引用它们 函数返回导致未定义的行为。

因此,你必须推迟freeaddrinfo直到。{ 不再需要地址列表,或复制信息。 这有点麻烦,因为ai_addr可能指向a IPv4或IPv6套接字地址结构,长度不同。

以下代码演示了如何复制地址列表 到一个sockaddr_storage结构数组(足够大) 持有任何IP地址)。此代码尚未经过全面测试, 所以要小心使用它。

public func getaddrinfo(node: String, service: String, hints: addrinfo?) throws -> [sockaddr_storage] {
    var err: Int32
    var res: UnsafeMutablePointer<addrinfo>?
    if var hints = hints {
        err = getaddrinfo(node, service, &hints, &res)
    } else {
        err = getaddrinfo(node, service, nil, &res)
    }
    if err == EAI_SYSTEM {
        throw SystemError.getaddrinfo(err, errno)
    }
    if err != 0 {
        throw SystemError.getaddrinfo(err, nil)
    }
    defer {
        freeaddrinfo(res)
    }
    guard let firstAddr = res else {
        return []
    }

    var result = [sockaddr_storage]()
    for addr in sequence(first: firstAddr, next: { $0.pointee.ai_next }) {
        var sockAddr = sockaddr_storage()
        memcpy(&sockAddr, addr.pointee.ai_addr, Int(addr.pointee.ai_addrlen))
        result.append(sockAddr)
    }
    return result
}

说明: