swift 解压缩方案的单元测试期间,Xcode 14 UnsafePointer.withMemoryRebound抛出EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP)

xxls0lw8  于 2023-01-25  发布在  Swift
关注(0)|答案(1)|浏览(201)

bounty已结束。回答此问题可获得+50声望奖励。奖励宽限期将在23小时后结束。Muni Perez希望引起更多人关注此问题。

你好!
我尝试对一段代码运行单元测试,但在执行以下代码时,遇到EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP)异常:

/// Decompresses the data using the gzip deflate algorithm. Self is expected to be a gzip deflate
    /// stream according to [RFC-1952](https://tools.ietf.org/html/rfc1952).
    /// - returns: uncompressed data
    func gunzip() -> Data?
    {
        // 10 byte header + data +  8 byte footer. See https://tools.ietf.org/html/rfc1952#section-2
        let overhead = 10 + 8
        guard count >= overhead else { return nil }

        typealias GZipHeader = (id1: UInt8, id2: UInt8, cm: UInt8, flg: UInt8, xfl: UInt8, os: UInt8)
        let hdr: GZipHeader = withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> GZipHeader in
            // +---+---+---+---+---+---+---+---+---+---+
            // |ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
            // +---+---+---+---+---+---+---+---+---+---+
            return (id1: ptr[0], id2: ptr[1], cm: ptr[2], flg: ptr[3], xfl: ptr[8], os: ptr[9])
        }

        typealias GZipFooter = (crc32: UInt32, isize: UInt32)
        let ftr: GZipFooter = withUnsafeBytes { (bptr: UnsafePointer<UInt8>) -> GZipFooter in
            // +---+---+---+---+---+---+---+---+
            // |     CRC32     |     ISIZE     |
            // +---+---+---+---+---+---+---+---+
            return bptr.advanced(by: count - 8).withMemoryRebound(to: UInt32.self, capacity: 2) { ptr in
                return (ptr[0].littleEndian, ptr[1].littleEndian)
            }
        }

        // Wrong gzip magic or unsupported compression method
        guard hdr.id1 == 0x1f && hdr.id2 == 0x8b && hdr.cm == 0x08 else { return nil }

        let has_crc16: Bool = hdr.flg & 0b00010 != 0
        let has_extra: Bool = hdr.flg & 0b00100 != 0
        let has_fname: Bool = hdr.flg & 0b01000 != 0
        let has_cmmnt: Bool = hdr.flg & 0b10000 != 0

        let cresult: Data? = withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> Data? in
            var pos = 10 ; let limit = count - 8

            if has_extra {
                pos += ptr.advanced(by: pos).withMemoryRebound(to: UInt16.self, capacity: 1) {
                    return Int($0.pointee.littleEndian) + 2 // +2 for xlen
                }
            }
            if has_fname {
                while pos < limit && ptr[pos] != 0x0 { pos += 1 }
                pos += 1 // skip null byte as well
            }
            if has_cmmnt {
                while pos < limit && ptr[pos] != 0x0 { pos += 1 }
                pos += 1 // skip null byte as well
            }
            if has_crc16 {
                pos += 2 // ignoring header crc16
            }

            guard pos < limit else { return nil }
            let config = (operation: COMPRESSION_STREAM_DECODE, algorithm: COMPRESSION_ZLIB)
            return perform(config, source: ptr.advanced(by: pos), sourceSize: limit - pos)
        }

        guard let inflated = cresult                                   else { return nil }
        guard ftr.isize == UInt32(truncatingIfNeeded: inflated.count)  else { return nil }
        guard ftr.crc32 == inflated.crc32().checksum                   else { return nil }
        return inflated
    }

fileprivate extension Data {
    func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
    {
        return try self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> ResultType in
            return try body(rawBufferPointer.bindMemory(to: ContentType.self).baseAddress!)
        })
    }
}

这部分代码总是抛出上述异常:

这个问题一直在发生,这段代码已经有2年没有碰过了,在MacOS 10.15的云管道(Azure)中运行也没有失败
它在运行 Monterey (12.6)和Xcode 14的多台MacOS设备上失败。
有人知道是什么引起的吗?
我知道这个问题很模糊,但这是我唯一的背景。
谢谢

fcwjkofz

fcwjkofz1#

根据您提供的代码段,没有明显的错误会导致EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP)异常。该错误似乎与内存管理有关,代码使用了指针,bptr指向的内存似乎无效或与withMemoryRebound函数中指定的类型不匹配。
导致此问题的一个可能原因是代码需要特定的内存布局或对齐方式,而新版本的macOS上不存在。您可以尝试以下几种方法:

  • 更新代码以使用最新的Swift语法和功能,这将帮助您避免弃用方法,也帮助您避免指针相关错误。
  • 在旧版本的macOS和Xcode上运行代码,查看是否可以解决问题。
  • 检查环境中是否缺少任何系统库,或者是否有任何系统库已过时。
  • 尝试在模拟器或仿真器上运行代码,看看是否可以解决问题,这将帮助您了解问题是否与特定设备或操作系统版本有关
  • 尝试使用一些调试工具,如lldb来跟踪问题,看看是哪个指令导致了错误,这将帮助您了解问题并修复它。

相关问题