简体   繁体   中英

Sometimes methods fails with Fatal error: UnsafeMutablePointer.initialize overlapping range

I have the following code to decompress some Data back to a String in Swift 5. The method mostly works fine, but sometimes it fails with the following error message:

Thread 1: Fatal error: UnsafeMutablePointer.initialize overlapping range

extension Data
{
    func decompress(destinationSize: Int) -> String?
    {
        let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: destinationSize)

        let decodedString = self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> String? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                let decompressedSize = compression_decode_buffer(destinationBuffer, destinationSize, unsafePointer, self.count, nil, COMPRESSION_ZLIB)

                if decompressedSize == 0
                {
                    return String.empty
                }

                let string = String(cString: destinationBuffer)
                let substring = string.substring(0, decompressedSize)

                return substring
            }

            return nil
        }

        return decodedString
    }
}

The error occurs at the following line:

let string = String(cString: destinationBuffer)

Can someone please explain why this (sometimes) fails?

I have switched to the following code and now everything works fine (Swift 5):

import Compression

extension Data
{
    func compress() -> Data?
    {
        return self.withUnsafeBytes
        {
            dataBytes in

            let sourcePtr: UnsafePointer<UInt8> = dataBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)

            return self.perform(operation: COMPRESSION_STREAM_ENCODE, source: sourcePtr, sourceSize: self.count)
        }
    }

    func decompress() -> Data?
    {
        return self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> Data? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                return self.perform(operation: COMPRESSION_STREAM_DECODE, source: unsafePointer, sourceSize: self.count)
            }

            return nil
        }
    }

    fileprivate func perform(operation: compression_stream_operation, source: UnsafePointer<UInt8>, sourceSize: Int, preload: Data = Data()) -> Data?
    {
        guard sourceSize > 0 else { return nil }

        let streamBase = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
        defer { streamBase.deallocate() }
        var stream = streamBase.pointee

        let status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
        guard status != COMPRESSION_STATUS_ERROR else { return nil }
        defer { compression_stream_destroy(&stream) }

        var result = preload
        var flags: Int32 = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
        let blockLimit = 64 * 1024
        var bufferSize = Swift.max(sourceSize, 64)

        if sourceSize > blockLimit
        {
            bufferSize = blockLimit
        }

        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        defer { buffer.deallocate() }

        stream.dst_ptr  = buffer
        stream.dst_size = bufferSize
        stream.src_ptr  = source
        stream.src_size = sourceSize

        while true
        {
            switch compression_stream_process(&stream, flags)
            {
                case COMPRESSION_STATUS_OK:
                    guard stream.dst_size == 0 else { return nil }
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    stream.dst_ptr = buffer
                    stream.dst_size = bufferSize

                    if flags == 0 && stream.src_size == 0
                    {
                        flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
                    }

                case COMPRESSION_STATUS_END:
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    return result

                default:
                    return nil
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM