godot-rust / godot-rust/gdext

Implementing a get_property_list(&mut self) method triggers the main thread check panic

Open
#1,427 6 comments 1 reaction 0 assignees View on GitHub
bug c: engine c: threads
Dominant language
Rust
Stars
5.2k
Forks
312
Avg merge
12h 16m
Merged PRs (30d)
11

Description

I'm trying to implement an advanced resource that interacts with the editor, changing its property list at runtime.

After experimenting, I noticed that Godot calls _get_property_list from a different thread, resulting in my program panicking and crashing the engine.
Stacktrace:

```
[panic backtrace]
0: std::backtrace::Backtrace::create
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src\..\..\backtrace\src\backtrace/win64.rs:85:14
1: std::backtrace::Backtrace::capture
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src/backtrace.rs:296:9
2: godot_core::private::set_gdext_hook::{{closure}}
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-core-0.4.3/src/private.rs:320:44
3: std::panicking::panic_with_hook
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\alloc\src/boxed.rs:1999:9
4: std::panicking::panic_handler::{{closure}}
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src/panicking.rs:700:13
5: std::sys::backtrace::__rust_end_short_backtrace
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src\sys/backtrace.rs:174:18
6: __rustc::rust_begin_unwind
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src/panicking.rs:698:5
7: core::panicking::panic_fmt
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\core\src/panicking.rs:75:14
8: godot_ffi::binding::single_threaded::BindingStorage::ensure_main_thread
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-ffi-0.4.3/src/binding/single_threaded.rs:152:17
9: godot_ffi::binding::single_threaded::BindingStorage::get_binding_unchecked
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-ffi-0.4.3/src/binding/single_threaded.rs:124:9
10: godot_ffi::binding::get_binding
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-ffi-0.4.3/src/binding/mod.rs:267:5
11: godot_ffi::binding::get_interface
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-ffi-0.4.3/src/binding/mod.rs:116:6
12: >::from::{{closure}}
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-core-0.4.3/src/builtin/string/string_name.rs:362:17
13: godot_core::builtin::string::string_name::StringName::new_with_string_uninit
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-ffi-0.4.3/src/godot_ffi.rs:199:13
14: >::from
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-core-0.4.3/src/builtin/string/string_name.rs:361:13
15: >::into
at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb\library\core\src\convert\mod.rs:778:9
16: ::get_property_list
at /mnt/e/clipmap/src/clipmap.rs:26:47
17: ::__godot_get_property_list
at /mnt/e/clipmap/src/clipmap.rs:19:1
18: godot_core::registry::callbacks::get_property_list
at /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-core-0.4.3/src/registry/callbacks.rs:326:25
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
ERROR:
[panic /home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-core-0.4.3/src/storage/mod.rs:38]
Gd::bind_mut() failed, already bound; T = clipmap::clipmap::ClipmapMesh.
Make sure to use `self.base_mut()` instead of `self.to_gd()` when possible.
Details: cannot borrow while accessible mutable borrow exists.
at: godot_core::private::set_gdext_hook::{{closure}} (/home/.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/godot-
core-0.4.3/src/private.rs:343)
fatal runtime error: failed to initiate panic, error 5, aborting
```

Relevant part of the code:

```rust
#[godot_api]
impl IPrimitiveMesh for ClipmapMesh {
fn get_property_list(&mut self) -> Vec {
let mut res = Vec::new();
res.push(PropertyInfo{
variant_type: VariantType::INT,
class_id: ClassId::none(),
property_name: "clipmap/number_of_lods".into(),
hint_info: PropertyHintInfo::none(),
usage: PropertyUsageFlags::EDITOR | PropertyUsageFlags::STORAGE,
});
// TODO: add more properties here
res
}
}
```

I am cross-compiling a `dll` from under a WSL terminal using

```bash
$ cargo build --target=x86_64-pc-windows-gnu
```

Adding the `experimental-threads` crate feature fixes this (by removing the check, I presume); but it feels like such basic functionality shouldn't rely on an experimental crate feature.

Contributor guide

Open the contributing guide

Research direction

Start at the get_property_list callback and trace the stack into godot_ffi/binding/single_threaded.rs, especially ensure_main_thread and get_binding. Then inspect the StringName conversion in godot_core/builtin/string/string_name.rs to understand why this callback reaches the main-thread guard. Done means reproducing the editor property-list update without a panic or engine crash, with coverage for the callback path.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.