Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer

后端 未结 1 1323
囚心锁ツ
囚心锁ツ 2021-02-20 18:21

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 f

相关标签:
1条回答
  • 2021-02-20 18:58

    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).

    0 讨论(0)
提交回复
热议问题