swift - 将 [UInt8] 数组转换为 xinpgen 结构

标签 swift memory struct memory-layout

我有以下代码来获取有关 tcp 端口的信息:

var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0)
{
    perror("sysctlbyname")
}
else
{
    var buffer: [UInt8] = [UInt8](repeating: 0, count: Int(length))
    sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0)
}

我现在想将缓冲区转换成更“有用”的东西。我读到返回值是一个名为“xinpgen”的结构。 如何将缓冲区转换为该结构?

我尝试了下面的代码直接将结果写入struct变量:

var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0)
{
    perror("sysctlbyname")
}
else
{
    var input = xinpgen()
    sysctlbyname("net.inet.tcp.pcblist", &input, &length, nil, 0)
}

调用本身并没有失败,而且似乎是成功的。该变量包含一些不为零的数据。但是在调用结束并且程序继续运行后不久,应用程序崩溃了:

error: memory read failed for 0x0

如何使用缓冲区来填充结构变量?为什么第二次调用失败?

最佳答案

sysctlbyname("net.inet.tcp.pcblist", ...)返回的数据 不是一个单一的xinpgen结构,而是一个“打包列表” 结构。

您的代码将更多字节写入输入的内存地址 比它的大小可变,行为是未定义的并且崩溃非常 可能。

我不知道返回数据的结构是否有文档记录,但是 inet.c 的源代码展示了它是如何被解析的。 显然,缓冲区以 struct xinpgen 开头,然后是 由可变数量的 struct xtcpcb 组成,每个元素都有 一个长度字段,其中包含到下一个结构的偏移量。

这是我尝试翻译上述源代码的 C 代码 文件到 Swift:

var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) {
    fatalError("sysctlbyname")
}

var buffer = [UInt8](repeating: 0, count: Int(length))
sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0)

buffer.withUnsafeBytes { bufPtr in

    // Pointer to first xinpgen structure:
    var p = bufPtr.baseAddress!
    var xig = p.bindMemory(to: xinpgen.self, capacity: 1)

    // Skip first xinpgen structure:
    p += Int(xig.pointee.xig_len)
    xig = p.bindMemory(to: xinpgen.self, capacity: 1)

    while Int(xig.pointee.xig_len) > MemoryLayout<xinpgen>.size {
        // Cast xig to xtcpcb pointer and derefernce:
        let tcpcb = xig.withMemoryRebound(to: xtcpcb.self, capacity: 1) {
            $0.pointee
        }
        print(tcpcb)

        // Advance pointer to next structure
        p += Int(xig.pointee.xig_len)
        xig = p.bindMemory(to: xinpgen.self, capacity: 1)
    }
}

关于swift - 将 [UInt8] 数组转换为 xinpgen 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44474144/

相关文章:

c++ - 在其赋值运算符方法中调用对象的析构函数

vb.net - 将大文件存储到SQLite的内存不足错误

c - 如何使用字符串声明作为实际成员的表示来调用结构的成员?

ios - 如果对象无效,如何检查 Swift?

ios - 仅在 x 轴上移动 Sprite

swift - 在 Swift 中存储指向变量的指针

memory - 关于使用 mfence/lfence/sfence 对第二个线程可见的锁中的数据修改的 Peterson 算法

c - 如何匿名申报

c - Cygwin 中的段错误和默认变量初始化

ios - 如何从父 ios 应用程序调用 watchkit 扩展中的方法