Warning: Initialization of 'UnsafeBufferPointer<T>' results in a dangling buffer pointer
I also met these annoying warnings.
var str = "aaaaabbbbbccccc"var num1 = 1var num2 = 22var data = Data()// Initialization of 'UnsafeBufferPointer<String>' results in a dangling buffer pointerdata.append(UnsafeBufferPointer(start: &str, count: 1)) // Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointerdata.append(UnsafeBufferPointer(start: &num1, count: 1))// Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointer data.append(UnsafeBufferPointer(start: &num2, count: 1))
Considering @greg's answer, I put the Data.append
into withUnsafePointer
's closure, and it does not show warnings anymore.
withUnsafePointer(to: &str) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // okwithUnsafePointer(to: &num1) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // okwithUnsafePointer(to: &num2) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok
Here is the extension
extension Data { init<T>(value: T) { self = withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) -> Data in return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) } } mutating func append<T>(value: T) { withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) in append(UnsafeBufferPointer(start: ptr, count: 1)) } }}
I had code which looked almost exactly what you were doing and was getting the same warning. Mine differed slightly in a way which is relevant to the discussion
init<T>(from value: T) { var value = value self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))}
This still generates the warning that UnsafeBufferPointer is producing a dangling Pointer but the hints say "produces a pointer valid only for the duration of the call to 'init(start:count:)'"
But the return from UnsafeBufferPointer isn't assigned to anything, so I couldn't use it outside the scope of the init if I tried. So the compiler here is warning me against doing something I can't do anyway.
I guess Data.init(buffer: ) could be storing the ptr, but I would assume that if it accepts an UnsafeBufferPointer, it's accepting the responsibility for using it properly
Anyway, that still doesn't really fix your problem. I got around the warning with this
init<T>(from value: T) { var value = value var myData = Data() withUnsafePointer(to:&value, { (ptr: UnsafePointer<T>) -> Void in myData = Data( buffer: UnsafeBufferPointer(start: ptr, count: 1)) }) self.init(myData)}
And this does not generate the warning and appears to work (in my application anyway). Whether it passes muster with the experts here is another matter.
Kind of makes me nostalgic for the days of HLock and HUnlock
This was never safe, so glad that the Swift team has cleaned it up:
let pointer = UnsafeBufferPointer(start: &value, count: 1)
At the end of this line of code, pointer
is immediately invalid. There is not promise that value
even exists at the next line of code. I'm not sure what you were trying to achieve here, but this was never a safe way to do it. What you're likely looking for is one of the .withUnsafeBytes
methods, which depends on what you were working on.