Skip to content

Commit afbd2cd

Browse files
bors[bot]BromeonthebigGlilizoey
authored
Merge #204
204: Fix various issues with pointer calls r=Bromeon a=sayaks Combines #165 and #200 with more complete fixes. # Overview Properly clones strings and shares arrays/dictionaries in pointer calls to ensure they're not prematurely freed. Frees the value currently in the `ret` pointer in pointer calls, to avoid memory leak. Moves `ret_val` into `ret`, to avoid premature destruction. Changes integer conversions in pointer calls to use `as`, since that seems like the right way of converting the values we get from godot. `try_from` lead to wrong conversions sometimes. Objects inheriting from `RefCounted` now use `ref_get_object` and `ref_set_object` in virtual method calls. # Details Add `from_arg_ptr` and `move_return_ptr` to `GodotFfi` that will be used when converting argument pointers in pointer calls, and moving things into a pointer. Add `CallType` so `from_arg_ptr` and `move_return_ptr` can have different behavior depending on whether it's a virtual method call or not. Remove `write_sys` in `GodotFfi`. Override `from_arg_ptr` in `GodotString`, `NodePath`, `StringName`, `Array`, `Dictionary`, `Gd`. Override `move_return_ptr` in `Gd`. Rename `try_write_sys` to `try_return`, and have it use `move_return_ptr` instead of `write_sys`. Rename `try_from_sys` to `try_from_arg`, and have it use `from_arg_ptr` instead of `from_sys`. Add `u8`, `u16`, `u32` to the ptrcall tests. Add a couple of test of virtual methods. Fix a test for virtual method with return values to actually call the virtual method as a virtual method. closes #195 closes #189 Co-authored-by: Jan Haller <[email protected]> Co-authored-by: thebigG <[email protected]> Co-authored-by: Lili Zoey <[email protected]>
2 parents 558a6d3 + 8206697 commit afbd2cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1069
-328
lines changed

godot-codegen/src/central_generator.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ fn make_sys_code(central_items: &CentralItems) -> String {
176176
}
177177
}
178178

179-
impl GodotFfi for VariantType {
179+
// SAFETY:
180+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
181+
unsafe impl GodotFfi for VariantType {
180182
ffi_methods! { type GDExtensionTypePtr = *mut Self; .. }
181183
}
182184

@@ -205,7 +207,9 @@ fn make_sys_code(central_items: &CentralItems) -> String {
205207
}
206208
}
207209

208-
impl GodotFfi for VariantOperator {
210+
// SAFETY:
211+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
212+
unsafe impl GodotFfi for VariantOperator {
209213
ffi_methods! { type GDExtensionTypePtr = *mut Self; .. }
210214
}
211215
};

godot-codegen/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ const SELECTED_CLASSES: &[&str] = &[
258258
"AudioStreamPlayer",
259259
"BaseButton",
260260
"Button",
261+
"BoxMesh",
261262
"Camera2D",
262263
"Camera3D",
263264
"CanvasItem",
@@ -271,9 +272,12 @@ const SELECTED_CLASSES: &[&str] = &[
271272
"Image",
272273
"ImageTextureLayered",
273274
"Input",
275+
"InputEvent",
276+
"InputEventAction",
274277
"Label",
275278
"MainLoop",
276279
"Marker2D",
280+
"Mesh",
277281
"Node",
278282
"Node2D",
279283
"Node3D",
@@ -283,9 +287,11 @@ const SELECTED_CLASSES: &[&str] = &[
283287
"PackedScene",
284288
"PathFollow2D",
285289
"PhysicsBody2D",
290+
"PrimitiveMesh",
286291
"RefCounted",
287292
"RenderingServer",
288293
"Resource",
294+
"ResourceFormatLoader",
289295
"ResourceLoader",
290296
"RigidBody2D",
291297
"SceneTree",
@@ -296,4 +302,6 @@ const SELECTED_CLASSES: &[&str] = &[
296302
"TextureLayered",
297303
"Time",
298304
"Timer",
305+
"Window",
306+
"Viewport",
299307
];

godot-codegen/src/util.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
9999
self.ord
100100
}
101101
}
102-
impl sys::GodotFfi for #enum_name {
102+
// SAFETY:
103+
// The enums are transparently represented as an `i32`, so `*mut Self` is sound.
104+
unsafe impl sys::GodotFfi for #enum_name {
103105
sys::ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
104106
}
105107
#bitfield_ops

godot-core/src/builtin/aabb.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ impl Aabb {
8282
*/
8383
}
8484

85-
impl GodotFfi for Aabb {
85+
// SAFETY:
86+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
87+
unsafe impl GodotFfi for Aabb {
8688
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
8789
}

godot-core/src/builtin/array.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,27 @@ impl<T: VariantMetadata + ToVariant> Array<T> {
566566
// ...
567567
// }
568568

569-
impl<T: VariantMetadata> GodotFfi for Array<T> {
570-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
569+
// SAFETY:
570+
// - `move_return_ptr`
571+
// Nothing special needs to be done beyond a `std::mem::swap` when returning an Array.
572+
// So we can just use `ffi_methods`.
573+
//
574+
// - `from_arg_ptr`
575+
// Arrays are properly initialized through a `from_sys` call, but the ref-count should be incremented
576+
// as that is the callee's responsibility. Which we do by calling `std::mem::forget(array.share())`.
577+
unsafe impl<T: VariantMetadata> GodotFfi for Array<T> {
578+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
579+
fn from_sys;
580+
fn sys;
581+
fn from_sys_init;
582+
fn move_return_ptr;
583+
}
584+
585+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
586+
let array = Self::from_sys(ptr);
587+
std::mem::forget(array.share());
588+
array
589+
}
571590

572591
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
573592
let mut result = Self::default();
@@ -855,7 +874,7 @@ macro_rules! varray {
855874
/// [`set_typed`](https://docs.godotengine.org/en/latest/classes/class_array.html#class-array-method-set-typed).
856875
///
857876
/// We ignore the `script` parameter because it has no impact on typing in Godot.
858-
#[derive(Debug, PartialEq, Eq)]
877+
#[derive(PartialEq, Eq)]
859878
struct TypeInfo {
860879
variant_type: VariantType,
861880
class_name: StringName,
@@ -880,3 +899,16 @@ impl TypeInfo {
880899
self.variant_type != VariantType::Nil
881900
}
882901
}
902+
903+
impl fmt::Debug for TypeInfo {
904+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905+
let class = self.class_name.to_string();
906+
let class_str = if class.is_empty() {
907+
String::new()
908+
} else {
909+
format!(" (class={class})")
910+
};
911+
912+
write!(f, "{:?}{}", self.variant_type, class_str)
913+
}
914+
}

godot-core/src/builtin/basis.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,9 @@ impl Mul<Vector3> for Basis {
570570
}
571571
}
572572

573-
impl GodotFfi for Basis {
573+
// SAFETY:
574+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
575+
unsafe impl GodotFfi for Basis {
574576
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
575577
}
576578

godot-core/src/builtin/color.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ impl Color {
311311
}
312312
}
313313

314-
impl GodotFfi for Color {
314+
// SAFETY:
315+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
316+
unsafe impl GodotFfi for Color {
315317
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
316318
}
317319

godot-core/src/builtin/dictionary.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,28 @@ impl Dictionary {
239239
// ----------------------------------------------------------------------------------------------------------------------------------------------
240240
// Traits
241241

242-
impl GodotFfi for Dictionary {
243-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
242+
// SAFETY:
243+
// - `move_return_ptr`
244+
// Nothing special needs to be done beyond a `std::mem::swap` when returning an Dictionary.
245+
// So we can just use `ffi_methods`.
246+
//
247+
// - `from_arg_ptr`
248+
// Dictionaries are properly initialized through a `from_sys` call, but the ref-count should be
249+
// incremented as that is the callee's responsibility. Which we do by calling
250+
// `std::mem::forget(dictionary.share())`.
251+
unsafe impl GodotFfi for Dictionary {
252+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
253+
fn from_sys;
254+
fn from_sys_init;
255+
fn sys;
256+
fn move_return_ptr;
257+
}
258+
259+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
260+
let dictionary = Self::from_sys(ptr);
261+
std::mem::forget(dictionary.share());
262+
dictionary
263+
}
244264

245265
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
246266
let mut result = Self::default();

godot-core/src/builtin/macros.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ macro_rules! impl_builtin_stub {
157157
}
158158
}
159159

160-
impl GodotFfi for $Class {
160+
// SAFETY:
161+
// This is simply a wrapper around an `Opaque` value representing a value of the type.
162+
// So this is safe.
163+
unsafe impl GodotFfi for $Class {
161164
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
162165
}
163166
};

godot-core/src/builtin/meta/mod.rs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ pub trait VariantMetadata {
2727
}
2828

2929
fn property_info(property_name: &str) -> PropertyInfo {
30-
PropertyInfo::new(
31-
Self::variant_type(),
32-
Self::class_name(),
33-
StringName::from(property_name),
34-
global::PropertyHint::PROPERTY_HINT_NONE,
35-
GodotString::new(),
36-
)
30+
PropertyInfo {
31+
variant_type: Self::variant_type(),
32+
class_name: Self::class_name(),
33+
property_name: StringName::from(property_name),
34+
hint: global::PropertyHint::PROPERTY_HINT_NONE,
35+
hint_string: GodotString::new(),
36+
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
37+
}
3738
}
3839

3940
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
@@ -52,33 +53,17 @@ impl<T: VariantMetadata> VariantMetadata for Option<T> {
5253
/// Rusty abstraction of sys::GDExtensionPropertyInfo
5354
/// Keeps the actual allocated values (the sys equivalent only keeps pointers, which fall out of scope)
5455
#[derive(Debug)]
56+
// Note: is not #[non_exhaustive], so adding fields is a breaking change. Mostly used internally at the moment though.
5557
pub struct PropertyInfo {
56-
variant_type: VariantType,
57-
class_name: ClassName,
58-
property_name: StringName,
59-
hint: global::PropertyHint,
60-
hint_string: GodotString,
61-
usage: global::PropertyUsageFlags,
58+
pub variant_type: VariantType,
59+
pub class_name: ClassName,
60+
pub property_name: StringName,
61+
pub hint: global::PropertyHint,
62+
pub hint_string: GodotString,
63+
pub usage: global::PropertyUsageFlags,
6264
}
6365

6466
impl PropertyInfo {
65-
pub fn new(
66-
variant_type: VariantType,
67-
class_name: ClassName,
68-
property_name: StringName,
69-
hint: global::PropertyHint,
70-
hint_string: GodotString,
71-
) -> Self {
72-
Self {
73-
variant_type,
74-
class_name,
75-
property_name,
76-
hint,
77-
hint_string,
78-
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
79-
}
80-
}
81-
8267
/// Converts to the FFI type. Keep this object allocated while using that!
8368
pub fn property_sys(&self) -> sys::GDExtensionPropertyInfo {
8469
use crate::obj::EngineEnum as _;

godot-core/src/builtin/meta/signature.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub trait SignatureTuple {
3434
ret: sys::GDExtensionTypePtr,
3535
func: fn(&mut C, Self::Params) -> Self::Ret,
3636
method_name: &str,
37+
call_type: sys::PtrcallType,
3738
);
3839
}
3940

@@ -143,6 +144,7 @@ macro_rules! impl_signature_for_tuple {
143144
ret: sys::GDExtensionTypePtr,
144145
func: fn(&mut C, Self::Params) -> Self::Ret,
145146
method_name: &str,
147+
call_type: sys::PtrcallType,
146148
) {
147149
$crate::out!("ptrcall: {}", method_name);
148150

@@ -151,19 +153,20 @@ macro_rules! impl_signature_for_tuple {
151153

152154
let args = ( $(
153155
unsafe {
154-
<$Pn as sys::GodotFuncMarshal>::try_from_sys(
155-
sys::force_mut_ptr(*args_ptr.offset($n))
156+
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
157+
sys::force_mut_ptr(*args_ptr.offset($n)),
158+
call_type
156159
)
157160
}
158161
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
159162
)* );
160163

161164
let ret_val = func(&mut *instance, args);
162-
unsafe { <$R as sys::GodotFuncMarshal>::try_write_sys(&ret_val, ret) }
163-
.unwrap_or_else(|e| return_error::<$R>(method_name, &e));
164-
165-
// FIXME is inc_ref needed here?
166-
// std::mem::forget(ret_val);
165+
// SAFETY:
166+
// `ret` is always a pointer to an initialized value of type $R
167+
// TODO: double-check the above
168+
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
169+
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
167170
}
168171
}
169172
};

godot-core/src/builtin/node_path.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,28 @@ impl NodePath {
2222
}
2323
}
2424

25-
impl GodotFfi for NodePath {
26-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
25+
// SAFETY:
26+
// - `move_return_ptr`
27+
// Nothing special needs to be done beyond a `std::mem::swap` when returning a NodePath.
28+
// So we can just use `ffi_methods`.
29+
//
30+
// - `from_arg_ptr`
31+
// NodePaths are properly initialized through a `from_sys` call, but the ref-count should be
32+
// incremented as that is the callee's responsibility. Which we do by calling
33+
// `std::mem::forget(node_path.share())`.
34+
unsafe impl GodotFfi for NodePath {
35+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
36+
fn from_sys;
37+
fn sys;
38+
fn from_sys_init;
39+
fn move_return_ptr;
40+
}
41+
42+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
43+
let node_path = Self::from_sys(ptr);
44+
std::mem::forget(node_path.clone());
45+
node_path
46+
}
2747

2848
unsafe fn from_sys_init_default(init_fn: impl FnOnce(GDExtensionTypePtr)) -> Self {
2949
let mut result = Self::default();
@@ -90,5 +110,7 @@ impl_builtin_traits! {
90110
Default => node_path_construct_default;
91111
Clone => node_path_construct_copy;
92112
Drop => node_path_destroy;
113+
Eq => node_path_operator_equal;
114+
// Ord => node_path_operator_less;
93115
}
94116
}

godot-core/src/builtin/packed_array.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,26 @@ macro_rules! impl_packed_array {
390390
}
391391
}
392392

393-
impl GodotFfi for $PackedArray {
394-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
393+
unsafe impl GodotFfi for $PackedArray {
394+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
395+
fn from_sys;
396+
fn sys;
397+
fn from_sys_init;
398+
// SAFETY:
399+
// Nothing special needs to be done beyond a `std::mem::swap` when returning a packed array.
400+
fn move_return_ptr;
401+
}
402+
403+
// SAFETY:
404+
// Packed arrays are properly initialized through a `from_sys` call, but the ref-count should be
405+
// incremented as that is the callee's responsibility.
406+
//
407+
// Using `std::mem::forget(array.clone())` increments the ref count.
408+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
409+
let array = Self::from_sys(ptr);
410+
std::mem::forget(array.clone());
411+
array
412+
}
395413

396414
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
397415
let mut result = Self::default();

godot-core/src/builtin/plane.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ impl Neg for Plane {
134134
}
135135
}
136136

137-
impl GodotFfi for Plane {
137+
// SAFETY:
138+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
139+
unsafe impl GodotFfi for Plane {
138140
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
139141
}
140142

0 commit comments

Comments
 (0)