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).
Swift Struct Warning Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer
Use withUnsafeMutableBytes
func foo() {
var parameters = MyParameters(position: .zero, size: 0)
withUnsafeMutableBytes(of: ¶meters) { pointer in
// here the lifetime is known
}
}
Initialization of 'UnsafePointer UInt8 ' 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)
CMVideoFormatDescriptionCreateFromH264ParameterSets throw Initialization of 'UnsafePointer Int ' 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
}
memset with Swift 5.2
The hint to use withUnsafeMutableBytes
is exactly what you should follow:
a.withUnsafeMutableBytes { ptr in
_ = memset(ptr.baseAddress! + start, 0, length)
}
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 UnsafeMutablePointer
s of any Pointee
types.
Related Topics
Get a Unique String for a Given Anyobject
Stopping an Running Skaction - Sprite Kit
Swiftui @Environmentobject Error: May Be Missing as an Ancestor of This View
Scene Kit Performance with Cube Test
Swift: How Can String.Join() Work Custom Types
Catch Objective-C Exception in Swift
Local Swift Packages Stopped Working in Xcode 13
Truncatingremainder VS Remainder in Swift
Xcode Autocomplete Does Not Work in Sources Folder of Swift Playgrounds
Swift + Nsviewcontroller Background Color (MAC App)
Swiftui - How to Set the Title of a Navigationview to Large Title (Or Small)
How to Pass Structure by Reference
Understanding @Binding in Swiftui
What's the Swift Equivalent of Objective-C's "#Ifdef _Iphone_11_0"