C array memory deallocation from swift - ios

var cpuInfo: processor_info_array_t = nil
var numCpuInfo: mach_msg_type_number_t = 0
var coresTotalUsage: Float = 0.0
var numCPUsU: natural_t = 0
let err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo);
assert(err == KERN_SUCCESS, "Failed call to host_processor_info")
Hi, I am calling the above C API host_processor_info to get process load informations from swift, no problem there.
cpuInfo is a inout parameter (pointer) that, on return, will point to a structure containing the CPU information allocated by that API.
The caller is reponsible for deallocating the memory; I can do that easily from objective C but haven't had any luck in swift. I know I could wrap that call into an objective C extension but I'm trying to learn swift and would like, if possible, avoid the obj-c solution.
in obj-c I would deallocate with:
size_t cpuInfoSize = sizeof(integer_t) * numCpuInfo;
vm_deallocate(mach_task_self(), (vm_address_t) cpuInfo, cpuInfoSize)
cpuInfo in swift is an UnsafeMutablePointer not convertible into a vm_address_t.
Any help appreciated, thanks.

processor_info_array_t is a pointer type, and vm_address_t is an integer type
(ultimately an alias for UInt). (Judging from the comments in <i386/vm_types.h>
this might to be for historical reasons.)
The only way to convert a pointer to an integer (of the same size) in Swift is unsafeBitCast.
mach_init.h defines
extern mach_port_t mach_task_self_;
#define mach_task_self() mach_task_self_
Only the extern variable is visible in Swift, not the macro.
This gives:
let cpuInfoSize = vm_size_t(sizeof(integer_t)) * vm_size_t(numCpuInfo)
vm_deallocate(mach_task_self_, unsafeBitCast(cpuInfo, vm_address_t.self), cpuInfoSize)

In Swift 4, the equivalent code appears to be:
let cpuInfoSize = vm_size_t(MemoryLayout<integer_t>.stride * Int(numCpuInfo))
vm_deallocate(mach_task_self_, vm_address_t(bitPattern: cpuInfo), cpuInfoSize)
In particular, the initializer UInt(bitPattern:) is now apparently preferred to unsafeBitCast() to initialize an unsigned integer with the bit pattern of a pointer (I guess this usage is not longer considered "unsafe"). It correctly handles a nil pointer, returning 0 in this case.

Related

How to pass out parameter to function from Swift FFI?

Let's say I have a function defined in Rust, which looks like this:
#[no_mangle]
pub unsafe extern "C" fn do_something(
my_value: *mut MyStruct,
some_param: c_uint,
content: *mut *mut u8,
length: *mut c_uint,
capacity: *mut c_uint,
) -> *mut MyStruct {
// Do something and obtain an `ffi_result`...
let heap_data = ffi_result.as_mut_ptr();
// These values are passed as "out" parameters.
*length = ffi_result.len() as c_uint;
*capacity = ffi_result.capacity() as c_uint;
*content = heap_data;
// We intentionally "leak" this data to the heap.
// The caller is responsible for cleaning it up by calling another function.
std::mem::forget(ffi_result);
std::boxed::Box::into_raw(value_of_type_my_struct)
}
It takes in a pointer to a struct, a simple integer parameter, several out parameters that can later be used to create an Array and it returns a pointer to a struct.
Now I compile the rust library into a static library for the target aarch64-apple-ios. I set up a XCode project, add the static library as a dependency as explained here with an "Objective-C Bridging Header" where I import the following header file
#ifndef libmy_project_h
#define libmy_project_h
#include <stdint.h>
struct myStruct;
struct myStruct *do_something(struct myStruct *state, int someParam, char **content, int *length, int *capacity);
#endif
Up until this point everything seems to work fine and I have already successfully used this procedure for a whole bunch of other functions. However in this special case I can not figure out how to call this function from swift. I need to call the function from swift and pass content, length and capacity as out parameters so that I can later use the pointers to create an Array in Swift like so.
This is what I tried so far:
var content = UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>(UnsafeMutablePointer(bitPattern: 0))
var length = UnsafeMutablePointer<Int32>(bitPattern: 0)
var capacity = UnsafeMutablePointer<Int32>(bitPattern: 0)
let my_struct = do_something(my_struct, Int32(some_param), content, length, capacity)
let buffer = UnsafeRawBufferPointer(start: content?.pointee, count: Int(length!.pointee))
var data = Array(repeating: UInt8(0), count: Int(length!.pointee))
data.withUnsafeMutableBytes { arrayPtr in
arrayPtr.copyBytes(from: buffer)
}
However now when I execute this swift snippet, I get an EXC_BAD_ACCESS error, which I think occurs because the pointers I manually created do not belong to the adress space of my application. How can I create pointers that I can use as out parameters?
P.S. For reference here is the same interop code in C#:
[DllImport("my_dll")]
private static extern IntPtr do_something(IntPtr state, uint someParam, out IntPtr content, out uint length, out uint capacity);
Which can be called like so:
IntPtr contentPointer;
uint length, capacity;
IntPtr my_struct = do_something(state, myParam, out contentPointer, out length, out capacity);
byte[] rawContent = new byte[length];
Marshal.Copy(contentPointer, rawContent, 0, (int)length);
// Free the data owned by rust with another FFI call:
free_do_something_result(contentPointer, length, capacity);
var length = UnsafeMutablePointer<Int32>(bitPattern: 0)
You need to pass storage for your out-parameters. This is defining a null pointer. When Rust tries to write the result to address 0, it crashes, since you don't have access to write there.
Instead of creating two layers of pointers, create a value of the type you want, and then pass the address (&) of that value; this will add the extra layer of pointer automatically.
// Create storage
var content: UnsafeMutablePointer<CChar>? // Could be NULL, so Optional
var length: Int32 = 0
var capacity: Int32 = 0
// Pass as references
do_something(&content, &length, &capacity)
// Copy the data
let data = Array(UnsafeRawBufferPointer(start: content, count: Int(length)))
content is still a pointer here because the thing being updated is a pointer. You're not providing storage for content, Rust is. But you do need to provide storage for the pointer (and that's what this does).
I can't compile your code because it's missing a lot (an MCVE would be much better here), so I can't test that this is doing exactly what you mean, but it should be close.
In your example, you're leaking the memory, but since your C# calls free_do_something_result (which I assume cleans it up), I assume you're actually doing the same in the Swift.

UnsafePointer<UInt8> initializer in Swift 3

I have a receipt validation class that is deprecated since Swift 3 has released. I fixed some issues, but I still have many ...
Here is the GitHub source code I used : https://gist.github.com/baileysh9/4386ea92b047d97c7285#file-parsing_productids-swift and https://gist.github.com/baileysh9/eddcba49d544635b3cf5
First Error :
var p = UnsafePointer<UInt8>(data.bytes)
Compiler throws : Cannot invoke initializer for type UnsafePointer(UInt8) with an argument list of type UnsafeRawPointer
Second error
while (ptr < end)
Binary operators < cannot be applied to two UnsafePointer(UInt8) operands
Thank you very much in advance :)
EDIT
Thanks to LinShiwei answer I found a solution to UnsafePointer declaration. It compiles but not tested yet (because other errors avoid me to test) :
func getProductIdFromReceipt(_ data:Data) -> String?
{
let tempData: NSMutableData = NSMutableData(length: 26)!
data.withUnsafeBytes {
tempData.replaceBytes(in: NSMakeRange(0, data.count), withBytes: $0)
}
var p: UnsafePointer? = tempData.bytes.assumingMemoryBound(to: UInt8.self)
In Swift 3, you cannot init an UnsafePointer using an UnsafeRawPointer.
You can use assumingMemoryBound(to:) to convert an UnsafeRawPointer into an UnsafePointer<T>. Like this:
var ptr = data.bytes.assumingMemoryBound(to: UInt8.self)
Use debugDescription or distance(to:) to compare two pointer.
while(ptr.debugDescription < endPtr.debugDescription)
or
while(ptr.distance(to:endPtr) > 0)
It is possible to put a regular pointer sign i C & in front of a Int8 array or Uint8 array to make a pointer to supply a C-function input. Like the &aBuffer array below (but the data array must copied locally first, to keep control of the storage of the data storage until finished with the operation, you get an error else). Here in a routine handling dropInteraction data (delivering a byte array):
func interpretInstanceData(filename: String, Buffer: [UInt8]) -> String {
var aBuffer = Buffer
let sInstanceData = String(cString: Ios_C_InterpretInstanceData(filename, &aBuffer, Int32(aBuffer.count)))
The question is slightly old. But googling for a solution on the topic of converting a swift byte array to a C-pointer (what else is UnsafePointer< UInt8 >). This question made a hit. But I think this answer is helpful for later editions of Swift (that I use). Would have worked even then. Worked in any kind of use needing a pointer from swift (just make the array of right type first).
May have recently changed to just this, without the ".bytes." part:
var p: UnsafePointer = data.assumingMemoryBound(to: UInt8.self)
from the original:
var p = UnsafePointer<UInt8>(data.bytes)

Converting C pointers to Swift 3

I have the code:
let data = Data(bytes: UnsafePointer<UInt8>(audioBuffer.mData), count: Int(bufferSize))
and
let u16 = UnsafePointer<Int32>(audioBuffer.mData).pointee
Both of which work in Swift 2.3 but not in Swift 3. How do I convert them so they act equivalently? (and why?)
To read 16-bit audio samples from Audio Unit callback buffers in Swift 3, I use:
let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
if var bptr = bufferPointer {
for i in 0..<(Int(frameCount)) {
let oneSampleI16 = bptr.assumingMemoryBound(to: Int16.self).pointee
// do something with the audio sample
bptr += 1
}
}
The rest of the Audio Session and Audio Unit code is in this gist: https://gist.github.com/hotpaw2/630a466cc830e3d129b9
I can't say I understand this well, nor have I read the document, but it looks like swift3 pointer casts are scoped to avoid or limit aliasing, so you can't (easily) have two different views of the same piece of memory, or at least not for very long. This means you must either copy the cast data out or do whatever you need to do within a cast callback.
Why eliminate aliasing? I guess it makes for happier compilers.
For Data:
// [NS]Data. probably copying the data
Data(bytes: audioBuffer.mData!, count: Int(audioBuffer.mDataByteSize))
For numeric arrays:
// cast the data to Int32s & (optionally) copy the data out
let umpInt32 = audioBuffer.mData!.assumingMemoryBound(to: Int32.self)
let frameCount = Int(audioBuffer.mDataByteSize/4)
var u32 = [Int32](repeating: 0, count: frameCount)
// copy data from buffer
u32.withUnsafeMutableBufferPointer {
$0.baseAddress!.initialize(from: umpInt32, count: frameCount)
}
p.s. there's some confusion in your code. is u16 supposed to be an array of Int32s? Or UInt16s? Or something else?
Check the latest reference of Data.init(bytes:count:).
The type of the parameter bytes is UnsafeRawPointer, which accepts UnsafeMutableRawPointer. And the type of AudioBuffer.mData is UnsafeMutableRawPointer?. You have no need to convert using initializer.
let data = Data(bytes: audioBuffer.mData!, count: Int(bufferSize))
(You just need to explicitly unwrap mData, as it is imported as nullable type, UnsafeMutableRawPointer?, but you need to pass non-nil UnsafeRawPointer (or UnsafeMutableRawPointer).
The second example, you'd better check what sort of methods are available for UnsafeMutableRawPointer. You can find load(fromByteOffset:as:) method, and can use it like this.
let i32 = audioBuffer.mData!.load(as: Int32.self)
`load(

Swift String from imported unsigned char 2D array

I am using a 3rd party C library in my iOS application, which I am in the process of converting from Objective-C to Swift. I hit an obstacle when attempting to read one of the structs returned by the C library in Swift.
The struct looks similar to this:
typedef unsigned int LibUint;
typedef unsigned char LibUint8;
typedef struct RequestConfiguration_ {
LibUint8 names[30][128];
LibUint numberNames;
LibUint currentName;
} RequestConfiguration;
Which is imported into Swift as a Tuple containing 30 Tuples of 128 LibUint8 values. After a long time of trial and error using nested withUnsafePointer calls, I eventually began searching for solutions to iterating a Tuple in Swift.
What I ended up using is the following functions:
/**
* Perform iterator on every children of the type using reflection
*/
func iterateChildren<T>(reflectable: T, #noescape iterator: (String?, Any) -> Void) {
let mirror = Mirror(reflecting: reflectable)
for i in mirror.children {
iterator(i.label, i.value)
}
}
/**
* Returns a String containing the characters within the Tuple
*/
func libUint8TupleToString<T>(tuple: T) -> String {
var result = [CChar]()
let mirror = Mirror(reflecting: tuple)
for child in mirror.children {
let char = CChar(child.value as! LibUint8)
result.append(char)
// Null reached, skip the rest.
if char == 0 {
break;
}
}
// Always null terminate; faster than checking if last is null.
result.append(CChar(0))
return String.fromCString(result) ?? ""
}
/**
* Returns an array of Strings by decoding characters within the Tuple
*/
func libUint8StringsInTuple<T>(tuple: T, length: Int = 0) -> [String] {
var idx = 0
var strings = [String]()
iterateChildren(tuple) { (label, value) in
guard length > 0 && idx < length else { return }
let str = libUint8TupleToString(value)
strings.append(str)
idx++
}
return strings
}
Usage
func handleConfiguration(config: RequestConfiguration) {
// Declaration types are added for clarity
let names: [String] = libUint8StringsInTuple(config.names, config.numberNames)
let currentName: String = names[config.currentName]
}
My solution uses reflection to iterate the first Tuple, and reflection to iterate the second, because I was getting incorrect strings when using withUnsafePointer for the nested Tuples, which I assume is due to signage. Surely there must be a way to read the C strings in the array, using an UnsafePointer alike withUsafePointer(&struct.cstring) { String.fromCString(UnsafePointer($0)) }.
To be clear, I'm looking for the fastest way to read these C strings in Swift, even if that involves using Reflection.
Here is a possible solution:
func handleConfiguration(var config: RequestConfiguration) {
let numStrings = Int(config.numberNames)
let lenStrings = sizeofValue(config.names.0)
let names = (0 ..< numStrings).map { idx in
withUnsafePointer(&config.names) {
String.fromCString(UnsafePointer<CChar>($0) + idx * lenStrings) ?? ""
}
}
let currentName = names[Int(config.currentName)]
print(names, currentName)
}
It uses the fact that
LibUint8 names[30][128];
are 30*128 contiguous bytes in memory. withUnsafePointer(&config.names)
calls the closure with $0 as a pointer to the start of that
memory location, and
UnsafePointer<CChar>($0) + idx * lenStrings
is a pointer to the start of the idx-th subarray. The above code requires
that each subarray contains a NUL-terminated UTF-8 string.
The solution suggested by Martin R looks good to me and, as far as I can see from my limited testing, does work. However, as Martin pointed out, it requires that the strings be NUL-terminated UTF-8. Here are two more possible approaches. These follow the principle of handling the complexity of C data structures in C instead of dealing with it in Swift. Which of these approaches you choose depends on what specifically you are doing with RequestConfiguration in your app. If you are not comfortable programming in C, then a pure Swift approach, like the one suggested by Martin, might be a better choice.
For the purposes of this discussion, we will assume that the 3rd party C library has the following function for retrieving RequestConfiguration:
const RequestConfiguration * getConfig();
Approach 1: Make the RequestConfiguration object available to your Swift code, but extract names from it using the following C helper function:
const unsigned char * getNameFromConfig(const RequestConfiguration * rc, unsigned int nameIdx)
{
return rc->names[nameIdx];
}
Both this function's signature and the RequestConfiguration type must be available to the Swift code via the bridging header. You can then do something like this in Swift:
var cfg : UnsafePointer<RequestConfiguration> = getConfig()
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig(cfg, cfg.memory.currentName)))
{
print(s)
}
This approach is nice if you need the RequestConfiguration object available to Swift in order to check the number of names in multiple places, for example.
Approach 2: You just need to be able to get the name at a given position. In this case the RequestConfiguration type does not even need to be visible to Swift. You can write a helper C function like this:
const unsigned char * getNameFromConfig1(unsigned int idx)
{
const RequestConfiguration * p = getConfig();
return p->names[idx];
}
and use it in Swift as follows:
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig1(2)))
{
print(s)
}
This will print the name at position 2 (counting from 0). Of course, with this approach you might also want to have C helpers that return the count of names as well as the current name index.
Again, with these 2 approaches it is assumed the strings are NUL-terminated UTF-8. There are other approaches possible, these are just examples.
Also please note that the above assumes that you access RequestConfiguration as read-only. If you also want to modify it and make the changes visible to the 3rd party library C code, then it's a different ballgame.

Swift: Errors when using different integer sizes

I've been trying out Swift, since it's obviously the direction that Apple wants us to go in.
However, I've been really annoyed with the fact that you can't seem to add integers of different sizes:
var a: Int64 = 1500
var b: Int32 = 12349
var c = a + b
if a < b { ... }
The yielded error is "Could not find an overload for '+' that accepts the supplied argument' — obviously since they are object types. None of the class methods seem to be of any help in up/down-converting integers.
Same situation applies with any of the type aliases, obviously, (CInt + CLong).
I can see a lot of real-world situations where it is immensely practical to be able to do integer arithmetic let alone comparisons or bitwise operations on two disparately-sized integers.
How to solve this? Explicit casting with the as operator doesn't seem to work. The Swift language book isn't much help either as it doesn't really discuss this scenario.
The Swift language book does discuss this scenario in the chapter “Numeric Type Conversion”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values.
let a: Int64 = 1500
let b: Int32 = 12349
let c = a + Int64(b)
println("The value of c is \(c)")

Resources