Initialization of 'Unsafepointer<Int>' Results in a Dangling Pointer

Initialization of 'UnsafePointerUInt8' results in a dangling pointer

Since Swift 3 it's possible to simply initialize a Data instance with an UInt8 array.

let sendBytes:[UInt8] = [0x0, 0x0, 0x5, 0x0]
let msgData = Data(sendBytes)

Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer

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

CMVideoFormatDescriptionCreateFromH264ParameterSets throw Initialization of 'UnsafePointerInt' results in a dangling pointer

When you find some error message like: Generic parameter 'R' could not be inferred, there may be two possible reasons.

  • There is some type-related error somewhere, so Swift cannot infer the actual type R in that context
  • The expression is a little more complex than Swift can infer the type

In case 1, you need to find where is the actual error causing the issue.

In case 2, you can add some explicit type annotations to help Swift infer the types.

Please try something like this:

    var formatDesc: CMVideoFormatDescription?
func createH264FormatDescription(SPS sps: Array<UInt8>, PPS pps: Array<UInt8>) -> OSStatus {
if formatDesc != nil { formatDesc = nil }

let status = sps.withUnsafeBufferPointer { spsBP->OSStatus in //<- Specify return type explicitly.
pps.withUnsafeBufferPointer { ppsBP in
let paramSet = [spsBP.baseAddress!, ppsBP.baseAddress!]
let paramSizes = [spsBP.count, ppsBP.count]
return paramSet.withUnsafeBufferPointer { paramSetBP in
paramSizes.withUnsafeBufferPointer { paramSizesBP in
CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault, parameterSetCount: 2, parameterSetPointers: paramSetBP.baseAddress!, parameterSetSizes: paramSizesBP.baseAddress!, nalUnitHeaderLength: 4, formatDescriptionOut: &formatDesc)
}
}
}
}
return status
}

UnsafeMutableBufferPointerAudioBuffer Speech To Text. Dangling Buffer Pointer

I am using the same AudioController. I have found the solution here

Code can be updated like this:

let buffers = withUnsafeMutablePointer(to: &bufferList.mBuffers) {
UnsafeMutableBufferPointer(start: $0, count: Int(bufferList.mNumberBuffers))
}
...
...
// get the recorded samples
status = withUnsafeMutablePointer(to: &bufferList) {
AudioUnitRender(AudioController.sharedInstance.remoteIOUnit!,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
$0)
}

Works for me fine

What does `UnsafeMutablePointer.initialize()`actually do?

One reason you need initialize(), and the only one as for now maybe, is

for ARC.

You'd better think with local scope variables, when seeing how ARC works:

func test() {
var refVar: RefType = initValue //<-(1)
//...
refVar = newValue //<-(2)
//...
//<-(3) just before exiting the loacl scope
}

For a usual assignment as (2), Swift generates some code like this:

swift_retain(_newValue)
swift_release(_refVar)
_refVar = _newValue

(Assume _refVar and _newValue are unmanaged pseudo vars.)

Retain means incrementing the reference count by 1, and release means decrementing the reference count by 1.


But, think what happens when the initial value assignment as at (1).

If the usual assignment code was generated, the code might crash at this line:

swift_release(_refVar)

because newly allocated region for a var may be filled with garbages, so swift_release(_refVar) cannot be safely executed.

Filling the newly region with zero (null) and release safely ignoring the null could be one solution, but it's sort of redundant and not effective.

So, Swift generates this sort of code for initial value assignment:

(for already retained values, if you know ownership model, owned by you.)

_refVar = _initValue

(for unretained values, meaning you have no ownership yet.)

swift_retain(_initValue)
_refVar = _initValue

This is initialize.

No-releasing the garbage data, and assign an initial value, retaining it if needed.

(The above explanation of "usual assignment" is a little bit simplified, Swift omits swift_retain(_newValue) when not needed.)


When exiting the local scope at (3), Swift just generates this sort of code:

swift_release(_refVar)

So, this is deinitialize.


Of course, you know retaining and releasing are not needed for primitive types like Int, so initialize and deinitialize may be donothing for such types.

And when you define a value type which includes some reference type properties, Swift generates initialize and deinitialize procedures specialized for the type.


The local scope example works for the regions allocated on the stack, and initialize() and deinitialize() of UnsafeMutablePointer works for the regions allocated in the heap.

And Swift is evolving so swift, that you might find another reason for needing initialize() and deinitialize() in the future, you'd better make it a habit to initialize() and deinitialize() all allocated UnsafeMutablePointers of any Pointee types.



Related Topics



Leave a reply



Submit