Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of 'UnsafePointer<Int>' results in a dangling pointer [duplicate]

Tags:

ios

swift

So I have some code to create H264ParameterSets like:

var formatDesc: CMVideoFormatDescription?

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

    let paramSet = [UnsafePointer<UInt8>(SPS), UnsafePointer<UInt8>(PPS)]
    let paramPointers = UnsafePointer<UnsafePointer<UInt8>>(paramSet)
    let paramSizes = UnsafePointer<Int>([SPS.count, PPS.count])

    let status = CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault, parameterSetCount: 2, parameterSetPointers: paramPointers, parameterSetSizes: paramSizes, nalUnitHeaderLength: 4, formatDescriptionOut: &formatDesc)

    return status
}

Starting on Xcode 11.4 I got warnings for those UnsafePointer(), which seems not happen before:

Initialization of UnsafePointer<UInt8> results in a dangling pointer

Initialization of UnsafePointer<UnsafePointer<UInt8>> results in a dangling pointer

Initialization of UnsafePointer<Int> results in a dangling pointer

I'm not sure why we see this? and how can I remove the warning? Thank in advance.

like image 383
Wingzero Avatar asked Apr 17 '20 02:04

Wingzero


1 Answers

The easiest way to explain this warning is to look at one of the cases causing it. So lets start with your use of SPS.

It is an Array<UInt8> so it is backed by a buffer of UInt8 just like in C. When you pass SPS with UnsafePointer<UInt8>(SPS) it creates a valid pointer to the buffer for that moment. The issue is that you could then mutate SPS say by appending another value to it. This would mean that the buffer backing the Array is potentially moved to another place in memory. This would mean that your pointer that is now part of paramSet is invalid.

The other issue is that if you pass this pointer to something, like you do in this case, the other function could try to hold onto it and then it has an invalid pointer. So if you expect the other function to hold onto the pointer you need to manually manage memory with UnsafePointers and Unmanaged yourself. If CMVideoFormatDescriptionCreateFromH264ParameterSets() doesn't hold onto the pointers then the code I'll share is correct, if it does you will need to adjust it to create/destory the memory as needed.

Also it is worth noting that in this case, you can't mutate any of the Arrays you have because they are constants but in general the principle is still the same. This means that in theory it could never be mutated but the Swift compiler prefers to help us write code that is always safe and correct whenever possible, even with UnsafePointer types.

So how can you fix this? You will need to be able to call withUnsafeBufferPointer and then access the pointer through the UnsafeBufferPointer like this:

var formatDesc: CMVideoFormatDescription?

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

    let status = SPS.withUnsafeBufferPointer { SPS in
        PPS.withUnsafeBufferPointer { PPS in
            let paramSet = [SPS.baseAddress!, PPS.baseAddress!]
            let paramSizes = [SPS.count, PPS.count]
            return paramSet.withUnsafeBufferPointer { paramSet in
                paramSizes.withUnsafeBufferPointer { paramSizes in
                    CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault, parameterSetCount: 2, parameterSetPointers: paramSet.baseAddress!, parameterSetSizes: paramSizes.baseAddress!, nalUnitHeaderLength: 4, formatDescriptionOut: &formatDesc)
                }
            }
        }
    }
    return status
}

The reason this approach works is that for the scope of withUnsafeBufferPointer the Law of Exclusivity is protecting the arrays so they can't be mutated.

If you are worried about the baseAddress! usage you can check that it isn't nil but it is guaranteed to not be nil when count > 0 according the the compiler engineers (they have stated this on either Twitter or the Swift forums I forget...).

like image 132
bscothern Avatar answered Oct 03 '22 14:10

bscothern