Inout expression creates a temporary pointer warning

Hello,


This code worked before upgrading to Xcode 11.4.1


  ///Double Complex vector phase radians
  static func phase(Real x:[Double], Imag y:[Double])->[Double] {
    guard (x.count == y.count) else {
      myLog(toFile: false, toCl:false, message: K.BOMB)
      return [0]
    }
    var real:[Double] = x
    var imaginary:[Double] = y
    var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)
    var results:[Double] = zeroD(npts:x.count)
    vDSP_zvphasD(&splitComplex, 1, &results, t, vDSP_Length(x.count))
    return results
  }


Now the warning


Inout expression creates a temporary pointer, but argument 'imagp' should be a pointer that outlives the call to 'init(realp:imagp:)'
Inout expression creates a temporary pointer, but argument 'realp' should be a pointer that outlives the call to 'init(realp:imagp:)'


What changed? Is there a quick fix?


Thanks.

Accepted Answer

Did you end up filing a bug report?

It is not a bug of Swift, but a bug of your code. Just that old Swift could not detect this sort of misusage and (if you think it was working) your code was seemingly working just by luck.


So I don't see what's up with the warning.

When you pass an Array to a pointer argument as an inout parameter, Swift allocates a temporary region for the Array, and passes the address of the temporary region to the function and call it, after finishing it, Swift releases the temporary region.


So, in your code, after finishing this line, `var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)`, your `splitComplex` may hold two already released memory region in `realp` and `imagp`.


In some conditions, Swift would pass the current address of the content of the Array, but the condition is not documented and may change in the future, also the current address of the content of the Array is not stable enough.


You should better update your code:

    static func phase(Real x:[Double], Imag y:[Double])->[Double] {
        guard (x.count == y.count) else {
            myLog(toFile: false, toCl:false, message: K.BOMB)
            return [0]
        }
        var real:[Double] = x
        var imaginary:[Double] = y
        var results:[Double] = zeroD(npts: x.count)
        real.withUnsafeMutableBufferPointer {realBP in
            imaginary.withUnsafeMutableBufferPointer {imaginaryBP in
                var splitComplex = DSPDoubleSplitComplex(realp: realBP.baseAddress!, imagp: imaginaryBP.baseAddress!)
                vDSP_zvphasD(&splitComplex, 1, &results, t, vDSP_Length(x.count))
            }
        }
        return results
    }

Answers

Seems to be the same issue, and solution, as here:


https://forums.developer.apple.com/thread/131952

Thanks for reply, yes it looks like the same issue. Did you end up filing a bug report?


The headers for this DSP function is


public struct DSPSplitComplex {

    public var realp: UnsafeMutablePointer

    public var imagp: UnsafeMutablePointer

    public init(realp: UnsafeMutablePointer, imagp: UnsafeMutablePointer)
}


So I don't see what's up with the warning.

No, I did not file a bug report.


You should, at least against documentation, as advised in the other thread.


More important: have you found a way to solve the warning with something similar ?

Did you end up filing a bug report?

It is not a bug of Swift, but a bug of your code. Just that old Swift could not detect this sort of misusage and (if you think it was working) your code was seemingly working just by luck.


So I don't see what's up with the warning.

When you pass an Array to a pointer argument as an inout parameter, Swift allocates a temporary region for the Array, and passes the address of the temporary region to the function and call it, after finishing it, Swift releases the temporary region.


So, in your code, after finishing this line, `var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)`, your `splitComplex` may hold two already released memory region in `realp` and `imagp`.


In some conditions, Swift would pass the current address of the content of the Array, but the condition is not documented and may change in the future, also the current address of the content of the Array is not stable enough.


You should better update your code:

    static func phase(Real x:[Double], Imag y:[Double])->[Double] {
        guard (x.count == y.count) else {
            myLog(toFile: false, toCl:false, message: K.BOMB)
            return [0]
        }
        var real:[Double] = x
        var imaginary:[Double] = y
        var results:[Double] = zeroD(npts: x.count)
        real.withUnsafeMutableBufferPointer {realBP in
            imaginary.withUnsafeMutableBufferPointer {imaginaryBP in
                var splitComplex = DSPDoubleSplitComplex(realp: realBP.baseAddress!, imagp: imaginaryBP.baseAddress!)
                vDSP_zvphasD(&splitComplex, 1, &results, t, vDSP_Length(x.count))
            }
        }
        return results
    }

I’m going to recommend that you watch WWDC 2019 Session 718 Introducing Accelerate for Swift. This describes a new, Swift-friendly interface to the Accelerate framework. For example,

vDSP_zvphasD(_:_:_:_:_:)
becomes
phase(_:result:)
. While it won’t solve all problems like this —
DSPDoubleSplitComplex
is still a pain to work with — I suspect it will help a lot.

Apropos

DSPDoubleSplitComplex
specifically, if I were working with that type a lot, I’d take OOPer’s code and wrap it in a helper function that calls a closure built with a value built from the two arrays. For example:
extension DSPDoubleSplitComplex {

    /// Calls a closure with a `DSPDoubleSplitComplex` based on the supplied real and imaginary arrays.
    ///
    /// - Warning: While `DSPDoubleSplitComplex` contains mutable pointers, the
    /// supplied closure must not mutate the buffers they point to.

    static func with<Result>(real: [Double], imaginary: [Double], _ body: (DSPDoubleSplitComplex) -> Result) -> Result {
        precondition( !real.isEmpty )
        precondition( !imaginary.isEmpty )
        precondition( real.count == imaginary.count )
        return real.withUnsafeBufferPointer { realBuf in
            return imaginary.withUnsafeBufferPointer { imaginaryBuf in
                let realPtr = UnsafeMutablePointer(mutating: realBuf.baseAddress!)
                let imaginaryPtr = UnsafeMutablePointer(mutating: imaginaryBuf.baseAddress!)
                let splitComplex = DSPDoubleSplitComplex(realp: realPtr, imagp: imaginaryPtr)
                return body(splitComplex)
            }
        }
    }
}

That makes the final

phase(…)
function really easy:
static func phase(real: [Double], imaginary: [Double]) -> [Double] {
    DSPDoubleSplitComplex.with(real: real, imaginary: imaginary) { splitComplex in
        var result = [Double](repeating: 0.0, count: real.count)
        vDSP.phase(splitComplex, result: &result)
        return result
    }
}

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"