vala genie freeing memory - glib

My understanding is that Vala and Genie have reference counting rather than garbage collection.
Per Valadoc.org, this:
string path = Path.build_filename ("my", "full", "path/to.txt");
yields this:
a newly-allocated string that must be freed with g_free
Is this correct or is g_free not required due to reference counting?
If string is wrapped within an object will g_free on string be actioned on object destruction?

Valadoc contains the documentation from the original GLib, GObject, Gtk+, etc. libraries. It also contains additional Vala specific documentation on top of that.
You often see sentences which only makes sense in the context of the C programming language.
The Vala compiler does the memory management for you (most of the time). In this example a Vala string is actually translated by the Vala compiler to a gchar * in C where it has to be deallocated using g_free which the Vala compiler also does for you.
As a matter of fact strings are a bit different than objects as they are not reference counted, but copied instead.
Take this example in Vala:
int main () {
Object obj1 = new Object ();
Object obj2 = obj1;
string s1 = "";
string s2 = s1;
return 0;
}
The (manually cleaned up) code that valac produces in C looks like this:
int main (void) {
GObject* obj1 = g_object_new (G_TYPE_OBJECT, NULL);
GObject* obj2 = g_object_ref (obj1);
gchar* s1 = g_strdup ("");
gchar* s2 = g_strdup (s1);
g_free (s2);
g_free (s1);
g_object_unref (obj2);
g_object_unref (obj1);
return 0;
}
As you can see obj2 is a reference to the same object as in obj1 and the object is only destroyed when both references are unrefed.
The string s2 on the other side is a copy of the string stored in s1 (which is in turn a copy of the string literal "").
As you can also see the compiler does take care of such details for you. It makes the manual reference counting and manual string copying automatic.

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.

File operation in drivers and struct declaration

i am trying to figure out how the code behind a basic kernel driver works.
I have the following struct:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
And my dev_open function is defined as:
static int dev_open(struct inode *, struct file *);
Now Im also familiar with the fact that the prototype for opening a device file is defined in the linux/fs.h:
http://lxr.linux.no/linux+v3.10/include/linux/fs.h#L1517
Here is the specific line from that link:
int (*open) (struct inode *, struct file *);
Now my question is what is the relationship between .open = dev_open, and int (*open) (struct inode *, struct file *);
which is defined in linux/fs.h? Is it passing the address of dev_open to the function pointer int (*open) defined in the linux/fs.h? There must be some relation or what is the point of defining the struct fops as type "file operation"?
A similar question was asked and answered here but i feel that my question was left out:
File operations in drivers
Thank you
I think this question is more about C than the Linux kernel.
Members of structure or union types cannot have function type, but they can have pointer to function type. For example, in the Linux kernel, the open member of struct file_operations needs to be declared with a pointer to function type: int (*open)(struct inode *, struct file *);. Declaring the member as int open(struct inode *, struct file *); is an error.
In this variable definition in Linux kernel code:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
Incidentally, the above should normally have the owner member initialized like so:
.owner = THIS_MODULE,
The expressions dev_open, dev_read, dev_write and dev_release are function designators being used as assignment expressions to initialize the members of fops. A function designator is an expression that has function type. Unless it is the operand of sizeof, _Alignof, or the unary & operator, a function designator is converted to a pointer to function type. Therefore, the above definition of variable foo is exactly equivalent to:
static struct file_operations fops =
{
.open = &dev_open,
.read = &dev_read,
.write = &dev_write,
.release = &dev_release,
};
(Don't forget to also initialize .owner = THIS_MODULE,.)
There, the function designators are operands of the unary & operator and so are not converted to pointer to function types implicitly, but the & operator is converting them to pointer to function types explicitly.
After the above initialization of fops, rc = fops.open(inode, file); indirectly calls dev_open(inode, file) and assigns the return value to rc. You may sometimes see this written in an older style: rc = (*fops.open)(inode, file);. They both do the same thing. The operand of the function call operator ( ) is in fact always a pointer to a function. In the case of rc = (*fops.open)(inode, file);, fops.open has a pointer to a function type. (*fops.open) dereferences fops.open to a function type but since (*fops.open) is a function designator it is implicitly converted back to a pointer to function type before the function call. Similarly, in the direct call rc = dev_open(inode, file);, dev_open is a function designator and so has a function type, but is implicitly converted to a pointer to function type before the function call.

Why can't I convert a Number into a Double?

weight is a field (Number in Firestore), set as 100.
int weight = json['weight'];
double weight = json['weight'];
int weight works fine, returns 100 as expected, but double weight crashes (Object.noSuchMethod exception) rather than returning 100.0, which is what I expected.
However, the following works:
num weight = json['weight'];
num.toDouble();
When parsing 100 from Firestore (which actually does not support a "number type", but converts it), it will by standard be parsed to an int.
Dart does not automatically "smartly" cast those types. In fact, you cannot cast an int to a double, which is the problem you are facing. If it were possible, your code would just work fine.
Parsing
Instead, you can parse it yourself:
double weight = json['weight'].toDouble();
Casting
What also works, is parsing the JSON to a num and then assigning it to a double, which will cast num to double.
double weight = json['weight'] as num;
This seems a bit odd at first and in fact the Dart Analysis tool (which is e.g. built in into the Dart plugin for VS Code and IntelliJ) will mark it as an "unnecessary cast", which it is not.
double a = 100; // this will not compile
double b = 100 as num; // this will compile, but is still marked as an "unnecessary cast"
double b = 100 as num compiles because num is the super class of double and Dart casts super to sub types even without explicit casts.
An explicit cast would be the follwing:
double a = 100 as double; // does not compile because int is not the super class of double
double b = (100 as num) as double; // compiles, you can also omit the double cast
Here is a nice read about "Types and casting in Dart".
Explanation
What happened to you is the following:
double weight;
weight = 100; // cannot compile because 100 is considered an int
// is the same as
weight = 100 as double; // which cannot work as I explained above
// Dart adds those casts automatically
You can do it in one line:
double weight = (json['weight'] as num).toDouble();
You can Parse the data Like given below:
Here document is a Map<String,dynamic>
double opening = double.tryParse(document['opening'].toString());
In Dart, int and double are separate types, both subtypes of num.
There is no automatic conversion between number types. If you write:
num n = 100;
double d = n;
you will get a run-time error. Dart's static type system allows unsafe down-casts, so the unsafe assignment of n to d (unsafe because not all num values are double values) is treated implicitly as:
num n = 100;
double d = n as double;
The as double checks that the value is actually a double (or null), and throws if it isn't. If that check succeeds, then it can safely assign the value to d since it is known to match the variable's type.
That's what's happening here. The actual value of json['weight'] (likely with static type Object or dynamic) is the int object with value 100. Assigning that to int works. Assigning it to num works. Assigning it to double throws.
The Dart JSON parser parses numbers as integers if they have no decimal or exponent parts (0.0 is a double, 0e0 is a double, 0 is an integer). That's very convenient in most cases, but occasionally annoying in cases like yours where you want a double, but the code creating the JSON didn't write it as a double.
In cases like that, you just have to write .toDouble() on the values when you extract them. That's a no-op on actual doubles.
As a side note, Dart compiled to JavaScript represents all numbers as the JavaScript Number type, which means that all numbers are doubles. In JS compiled code, all integers can be assigned to double without conversion. That will not work when the code is run on a non-JS implementation, like Flutter, Dart VM/server or ahead-of-time compilation for iOS, so don't depend on it, or your code will not be portable.
Simply convert int to double like this
int a = 10;
double b = a + 0.0;

Why must a struct value be mutable to set an indexed property?

Consider the following program:
[<Struct>]
type Grid2D<'T> =
val RowLength : int
val Data : 'T[]
new(rowLength, data) = { RowLength = rowLength; Data = data }
member this.Item
with get(rowIndex, columnIndex) =
this.Data.[rowIndex * this.RowLength + columnIndex]
and set(rowIndex, columnIndex) value =
this.Data.[rowIndex * this.RowLength + columnIndex] <- value
let g = Grid2D(3, Array.zeroCreate(3 * 3))
g.[1, 1] <- 4
The last line fails to compile with:
error FS0256: A value must be mutable in order to mutate the contents
or take the address of a value type, e.g. 'let mutable x = ...'
However, if the [<Struct>] attribute is removed, and Grid2D is thus a reference type, then the program compiles.
Interestingly, inlining the property setter by hand also compiles fine:
g.Data.[1 * g.RowLength + 1] <- 4
So why is calling it a compile error?
Note: I am aware that this compiler error exists to make it impossible to mutate a non-mutable value of a struct by setting one of its fields. But I'm clearly not mutating the struct here.
I'm gonna take a guess here that its the second part of that error message that applies - "or take the address of a value type". Its not the mutability but the address of the value type that needs to be taken in order for you to refer to the same value g when mutating the Data.
It's probably impossible the compiler could consistently prove any setter doesn't actually mutate the struct, so it doesn't bother and just always emits the error when using assignment statements on non-mutable struct bindings.
In other words the question becomes: why does F# assume property setters mutate their instance? Well, probably because that's usually what property setters do.
Inlining the property setter works in this case because then the target of the assignment is an element of a property and not a property of the struct itself.

Why Array.zeroCreate still fills null for non nullable type?

Does it imply that whenever I am passed an array of a non nullable type, I should still check if it is null? Actually it is not even possible to check <> null but have to use operator.unchecked .How is it better than C#?
type test=
{
value: int
}
let solution = Array.zeroCreate 10
solution.[0] <- {value = 1}
solution.[1].value // System.NullReferenceException: Object reference not set to an instance of an object
type test =
{value: int;}
val solution : test [] =
[|{value = 1;}; null; null; null; null; null; null; null; null; null|]
val it : unit = ()
It depends where the array is being passed from.
If the array is created and used only within F#, then no, you don't need to check for null; in fact, you shouldn't check for null (using Unchecked.defaultOf) because the F# compiler optimizes some special values like [] (and None, in certain cases) by representing them as null in the compiled IL.
If you're consuming an array being passed in by code written in another language (such as C#), then yes, you should still check for null. If the calling code just creates the array and doesn't mutate it any further, then you'll only need to perform the null checks once.
EDIT : Here's a previous discussion about how the F# compiler optimizes the representation of certain values using null: Why is None represented as null?
As the documentation for Array.zeroCreate indicates, it initializes the elements to Unchecked.defaultof<_>. This therefore carries with it all of the same caveats that direct use of Unchecked.defaultof does. Generally, my advice would be to use Array.create/Array.init whenever possible, and to treat Array.zeroCreate as a possible performance optimization (requiring care whenever dealing with non-nullable types).
You're creating a record type, which is implemented as a class, which is indeed nullable. If you intended to create a struct, your code should look something like this:
type test =
struct
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()
end
let solution = Array.zeroCreate 10
solution.[0] <- test(1)
This outputs: val solution : test [] = [|1; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
You could also write the type using the Struct attribute, saving you a level of indentation.
[<Struct>]
type test =
val value: int
new(v) = { value = v }
override x.ToString() = x.value.ToString()

Resources