Skip to content

Commit 3264197

Browse files
authored
Merge pull request #144 from NordSecurity/LLT-6597_backport_movable_reference_fix
[Backport #143] Fix callback vtable lifetime
2 parents 8cfc55c + 751c112 commit 3264197

File tree

5 files changed

+27
-18
lines changed

5 files changed

+27
-18
lines changed

.github/workflows/cs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: C#
22

33
on:
44
push:
5-
branches: [ "main" ]
5+
branches: [ "main", "main-v0.28.3" ]
66
pull_request:
7-
branches: [ "main" ]
7+
branches: [ "main", "main-v0.28.3" ]
88

99
env:
1010
CARGO_TERM_COLOR: always

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
### UNRELEASED
22

3+
### v0.9.2+v0.28.3
4+
- Fix vtable callback lifetimes
5+
36
### v0.9.1+v0.28.3
47
- Add calling convention cdecl to DllImport
58
- User type "String" shadows native type System.String [#110](https://github.com/NordSecurity/uniffi-bindgen-cs/issues/110)

bindgen/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "uniffi-bindgen-cs"
3-
version = "0.9.0+v0.28.3"
3+
version = "0.9.2+v0.28.3"
44
edition = "2021"
55

66
[lib]
@@ -28,4 +28,4 @@ toml = "0.5"
2828

2929
uniffi_bindgen.workspace = true
3030
uniffi_meta.workspace = true
31-
uniffi_udl.workspace = true
31+
uniffi_udl.workspace = true

bindgen/src/gen_cs/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ impl CsCodeOracle {
398398
FfiType::RustBuffer(_) => "RustBuffer".to_string(),
399399
FfiType::ForeignBytes => "ForeignBytes".to_string(),
400400
FfiType::Callback(_) => "IntPtr".to_string(),
401-
FfiType::Reference(typ) => format!("ref {}", self.ffi_type_label(typ, prefix_struct)),
401+
FfiType::Reference(typ) => format!("IntPtr /*{}*/", self.ffi_type_label(typ, prefix_struct)),
402402
FfiType::RustCallStatus => "UniffiRustCallStatus".to_string(),
403403
FfiType::Struct(name) => {
404404
if prefix_struct {
@@ -410,4 +410,4 @@ impl CsCodeOracle {
410410
FfiType::VoidPointer => "IntPtr".to_string(),
411411
}
412412
}
413-
}
413+
}

bindgen/templates/CallbackInterfaceImpl.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ class {{ callback_impl_name }} {
2222

2323
{%- match meth.return_type() %}
2424
{%- when Some with (return_type) %}
25-
@uniffiOutReturn = {{ return_type|ffi_converter_name }}.INSTANCE.Lower(result);
25+
unsafe {
26+
{%- let return_ffi_type = return_type|ffi_type %}
27+
*({{ return_ffi_type|ffi_type_name }}*)uniffiOutReturn = {{ return_type|ffi_converter_name }}.INSTANCE.Lower(result);
28+
}
2629
{%- when None %}
2730
{%- endmatch %}
2831

@@ -109,8 +112,10 @@ class {{ callback_impl_name }} {
109112
}, cts.Token);
110113

111114
var foreignHandle = _UniFFIAsync._foreign_futures_map.Insert(cts);
112-
@uniffiOutReturn.@handle = foreignHandle;
113-
@uniffiOutReturn.@free = Marshal.GetFunctionPointerForDelegate(_UniFFIAsync.UniffiForeignFutureFreeCallback.callback);
115+
unsafe {
116+
(*(_UniFFILib.UniffiForeignFuture*)uniffiOutReturn).handle = foreignHandle;
117+
(*(_UniFFILib.UniffiForeignFuture*)uniffiOutReturn).free = Marshal.GetFunctionPointerForDelegate(_UniFFIAsync.UniffiForeignFutureFreeCallback.callback);;
118+
}
114119
{%- endif %}
115120
} else {
116121
throw new InternalException($"No callback in handlemap '{handle}'");
@@ -128,16 +133,17 @@ static void UniffiFree(ulong @handle) {
128133
{%- endfor %}
129134
static _UniFFILib.UniffiCallbackInterfaceFree _callback_interface_free = new _UniFFILib.UniffiCallbackInterfaceFree(UniffiFree);
130135

131-
public static _UniFFILib.{{ vtable|ffi_type_name }} _vtable = new _UniFFILib.{{ vtable|ffi_type_name }} {
132-
{%- for (ffi_callback, meth) in vtable_methods.iter() %}
133-
{%- let fn_type = format!("_UniFFILib.{}Method", callback_impl_name) %}
134-
{{ meth.name()|var_name() }} = Marshal.GetFunctionPointerForDelegate(_m{{ loop.index0 }}),
135-
{%- endfor %}
136-
@uniffiFree = Marshal.GetFunctionPointerForDelegate(_callback_interface_free)
137-
};
138-
139136
public static void Register() {
140-
_UniFFILib.{{ ffi_init_callback.name() }}(ref {{ callback_impl_name }}._vtable);
137+
_UniFFILib.{{ vtable|ffi_type_name }} _vtable = new _UniFFILib.{{ vtable|ffi_type_name }} {
138+
{%- for (ffi_callback, meth) in vtable_methods.iter() %}
139+
{%- let fn_type = format!("_UniFFILib.{}Method", callback_impl_name) %}
140+
{{ meth.name()|var_name() }} = Marshal.GetFunctionPointerForDelegate(_m{{ loop.index0 }}),
141+
{%- endfor %}
142+
@uniffiFree = Marshal.GetFunctionPointerForDelegate(_callback_interface_free)
143+
};
144+
145+
// Pin vtable to ensure GC does not move the vtable across the heap
146+
_UniFFILib.{{ ffi_init_callback.name() }}(GCHandle.Alloc(_vtable, GCHandleType.Pinned).AddrOfPinnedObject());
141147
}
142148
}
143149

0 commit comments

Comments
 (0)