Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer

Tags:

swift

Since Xcode 11.4 I get the warning message "Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer"

for the following code where I read an SIMD4 from an MTLTexture into an array:

let texArray = Array<SIMD4<Float>>(repeating: SIMD4<Float>(repeating: 0), count: 1)

texture.getBytes(UnsafeMutableRawPointer(mutating: texArray), bytesPerRow: (MemoryLayout<SIMD4<Float>>.size * texture.width), from: region, mipmapLevel: 0)

Can somebody figure out how to create the array pointer to get rid of the warning ?

Thanks

like image 462
Markus Moenig Avatar asked Mar 26 '20 05:03

Markus Moenig


1 Answers

TLDR

make text array mutable (use var instead of let) and use withUnsafeMutableBytes

var texArray = Array<SIMD4<Float>>(repeating: SIMD4<Float>(repeating: 0), count: 1)
texArray.withUnsafeMutableBytes { texArrayPtr in
    texture.getBytes(texArrayPtr.baseAddress!, bytesPerRow: (MemoryLayout<SIMD4<Float>>.size * texture.width), from: region, mipmapLevel: 0)
}

Explanation

The warning was introduced because the compiler can't make sure that data backing the pointer will not be deallocated. Consider you have a function (e.g. implemented in C) manipulating some data pointed to.

func f(_ a: UnsafeMutablePointer<Int>){
  a[0] = 42
}

Then it must be made sure that memory was not deallocated until the end of the call. So when calling this function in the following way it is not safe

var a: = [1]
p: UnsafeMutablePointer<Int>(&a)
// at this point the compiler may optimise and deallocate 'a' since it is not used anymore
f(p)

Currently this won't be an issue as far as I know since local variables will not be deallocated before the end of the scope. One can illustrate the possible issue by introducing a nested scope in the following way

var p: UnsafeMutablePointer<Int>?
do {
  var a = [1]
  p = UnsafeMutablePointer<Int>(&a)
} // "a" will be deallocated here
// now "p" is a dangling pointer the compiler warned you of
var b = [0] // compiler will use same memory as for "a", so manipulating memory of "p" won't segfault
f(p!) // manipulate memory
print(b[0]) // prints 42 although "b" was initialised to 0

Due to the fact that b allocates the same memory that a was using before, the memory of b is modified by the call to f(p!). So b[0] is 42 although it was initialised to 0 and not explicitly modified.

With this illustration it should become clear why there are methods withUnsafeMutableBytes and withUnsafeMutableBufferPointer on Swift arrays and global functions withUnsafeMutablePointer plus immutable variants. (I personally find it confusing that methods must be used on arrays and and global functions on structs.) These functions make sure that memory is not deallocated (or reused) for the scope of the closure (I also created gist with some examples).

like image 176
dastrobu Avatar answered Oct 05 '22 12:10

dastrobu