Pointer and Malloc in Swift

Pointer and malloc in Swift

You can use malloc from Swift, it returns a "raw pointer":

var p: [UnsafeMutableRawPointer?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0

p[allocatedMB] = malloc(1048576)
memset(p[allocatedMB], 0, 1048576)

Alternatively, use UnsafeMutablePointer and its
allocate and initialize methods:

var p: [UnsafeMutablePointer<UInt8>?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0

p[allocatedMB] = UnsafeMutablePointer.allocate(capacity: 1048576)
p[allocatedMB]?.initialize(to: 0, count: 1048576)

Free C-malloc()'d memory in Swift?

Swift does not manage memory that is allocated with malloc(), you have to free the memory eventually:

let ret = the_function("something") // returns pointer to malloc'ed memory
let str = String.fromCString(ret)! // creates Swift String by *copying* the data
free(ret) // releases the memory

println(str) // `str` is still valid (managed by Swift)

Note that a Swift String is automatically converted to a UTF-8
string when passed to a C function taking a const char * parameter
as described in String value to UnsafePointer<UInt8> function parameter behavior.
That's why

let ret = the_function(("something" as NSString).UTF8String)

can be simplified to

let ret = the_function("something")

Converting Objective-C malloc to Swift

malloc and free actually work fine in Swift; however, the UnsafeMutablePointer API is more "native". I'd probably use Data's bytesNoCopy for better performance. If you want, you can use Data(bytes:count:), but that will make a copy of the data (and then you need to make sure to deallocate the pointer after making the copy, or you'll leak memory, which is actually a problem in the Objective-C code above since it fails to free the buffer).

So, something like:

func prepareEndPacket() -> Data {
let count = PACKET_SIZE + 5
let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: count)

PrepareEndPacket(buf)

return Data(bytesNoCopy: buf, count: count, deallocator: .custom { ptr, _ in
ptr.deallocate()
})
}

By using bytesNoCopy, the Data object returned is basically a wrapper around the original pointer, which will be freed by the deallocator when the Data object is destroyed.

Alternatively, you can create the Data object from scratch and get a pointer to its contents to pass to PrepareEndPacket():

func prepareEndPacket() -> Data {
var data = Data(count: PACKET_SIZE + 5)

data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
PrepareEndPacket(ptr)
}

return data
}

This is slightly less efficient, since the Data(count:) initializer will initialize all the Data's bytes to zero (similar to using calloc instead of malloc), but in many cases, that may not make enough of a difference to matter.

Swift: Interoperability of UnsafeMutablePointer.deallocate(capacity:) with free()

Documentation is unclear about this, but testing suggests interoperability.

Using malloc() in C, then calling deallocate() in Swift and trying to free() the pointer in C (or vice versa) will result in a run-time error, yet the code will run fine if only one of deallocate() or free() is used, but not both.

Similarly, allocating a structure in Swift, then using deallocate() in Swift and free() in C (or the other way around) will also result in a run-time error.

It is also OK to use free() in Swift as suggested by @jtbandes. In fact, this approach might be safer than calling deallocate().

As for documentation, see https://developer.apple.com/reference/swift/unsafemutablepointer.

Also, you can dig through the UnsafeMutablePointer's source code here: https://github.com/apple/swift/blob/master/stdlib/public/core/UnsafePointer.swift.gyb

I haven't had time to figure out the implementation yet.

Pointer being freed was not allocated [Swift]

The problem is that the buffer is allocated only once, but free'd every
time when

 String(bytesNoCopy: buffer, length: numberOfBytesRead, encoding: .ascii, freeWhenDone: true)

is called. Here is a short self-contained example demonstrating the problem:

let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 4)
memcpy(buffer, "abcd", 4)

var s = String(bytesNoCopy: buffer, length: 4, encoding: .ascii, freeWhenDone: true)
// OK

s = String(bytesNoCopy: buffer, length: 4, encoding: .ascii, freeWhenDone: true)
// malloc: *** error for object 0x101d8dc40: pointer being freed was not allocated

Using freeWhenDone: false would be one option to solve the problem, but note
that you have to free the buffer eventually.

An alternative is to use an Array (or Data) as buffer, this is automatically
released when the function returns. Example:

var buffer = [UInt8](repeating: 0, count: maxReadLength)
while inputStream.hasBytesAvailable {
let numberOfBytesRead = inputStream.read(&buffer, maxLength: maxReadLength)
if numberOfBytesRead < 0 {
break
}
if let receivedMsg = String(bytes: buffer[..<numberOfBytesRead], encoding: .ascii) {
// ...
}
}

What is the swift equivalent of this cast?

The first two of those are of type size_t, which maps to Uint in Swift, and the last is GLubyte, which maps to UInt8. This code will initialize spriteData as an array of GLubyte, which you could pass to any C function that needs an UnsafeMutablePointer<GLubyte> or UnsafePointer<GLubyte>:

let width = CGImageGetWidth(spriteImage)
let height = CGImageGetHeight(spriteImage)
var spriteData: [GLubyte] = Array(count: Int(width * height * 4), repeatedValue: 0)

What do you need to do with spriteData?



Related Topics



Leave a reply



Submit