Error in accessing Data "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"

Hey Guys,

I'm having troubles accessing (and extracting) bytes from data. I need to convert some types to bytes, put them together in a Data object and extracting back.

I used this to convert some types to Data

extension ExpressibleByBooleanLiteral {
    public init(from data: Data) {
        self = data.withUnsafeBytes {
            $0.pointee
        }
    }
    
    public var toData: Data {
        get {
            var value = self
            return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
        }
    }
}

I'm doing so for simple types (Int, UInt). I can convert Bool, Int, UInt to Data and append them in one big Data. But when I want to extract them this way, I get error :

extension Data {

private mutating func getBool() -> Bool {
    print(self)
    //1 bytes
    for v in self.enumerated() {
        print(v)
    }
    //(offset: 0, element: 1)
    let result = self.subdata(in: 0..<MemoryLayout<Bool>.size) //Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    self.removeFirst(MemoryLayout<Bool>.size)
    return Bool(from: result)

Data is there but I can't access it.
I get similar error with Int and I had to copy Data to a new buffer before accessing it. But this trick doesn't work for Bool...

    private mutating func getInteger<T: FixedWidthInteger>(type: T.Type) -> T {
        defer {
            self.removeFirst(MemoryLayout.size(ofValue: type))
        }
        let buffer = Data(self)
        return type.init(from: buffer.subdata(in: 0..<MemoryLayout.size(ofValue: type)))
    }

In my test, this is the call for the last byte. At the beginning, Data is 18 bytes long. When I breakpoint and debug, I see:

> self
   > _backing
       > _length = 18
       > _capacity = 18
       > _offset = 0
   > _sliceRange = 17..<18
       > lowerBound = 17
       > upperBound = 18

The next one works :

    private mutating func getBool() -> Bool {
        defer {
            self.removeFirst(MemoryLayout<Bool>.size)
        }
        let buffer = Data(self)
        return Bool(from: buffer.subdata(in: 0..<MemoryLayout<Bool>.size))
    }

But this one fails (accessing through self.getBool(type: Bool.self) :

private mutating func getBool<T: ExpressibleByBooleanLiteral>(type: T.Type) -> T {
    defer {
        self.removeFirst(MemoryLayout.size(ofValue: type))
    }
    let buffer = Data(self)
    return type.init(from: buffer.subdata(in: 0..<MemoryLayout.size(ofValue: type)))

}

I’m not sure what’s going on with your full example but I’m concerned about this line:

let result = self.subdata(in: 0..<MemoryLayout<Bool>.size)

where you assume that 0 is always a valid index for a Data value. That’s not the case because Data is its own slice type, so a value can represent a slice of some other value. Consider this code:

let d = "ABCD".data(using: .utf8)!
let sd = d.dropFirst()
print(d.startIndex)     // -> 0
print(d[0])             // -> 65, or ASCII 'A'
print(sd.startIndex)    // -> 1
print(sd[0])            // traps

This slicing is also used when you call mutating methods like removeFirst(_:).

When dealing with Data, you have to use startIndex rather than assuming it starts at 0.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"

My bad....
I didn't really understand how these slice types works...

You were absolutely right. 0 was not the beginning of the slice and I don't know why I was thinking 0..< Size instead of start..<start + size

Problem solved ! ;)
Thank you very much