godot-rust / gdext

Rust bindings for Godot 4
https://mastodon.gamedev.place/@GodotRust
Mozilla Public License 2.0
2.77k stars 167 forks source link

Exporting project in release configuration makes optinal Gd references empty without a debug build #664

Open lostlont opened 3 months ago

lostlont commented 3 months ago

Steps to reproduce

  1. Have a godot-rust library, a Godot project, and the two linked together with the gdextension file for both debug and release builds.
  2. Have a custom node type in the Rust library with an #[export] other: Option<Gd<Node>> value. Print its value in the ready function.
  3. Build the Rust library for release build and delete any debug build outputs.
  4. Open the Godot project, place a custom node, and any other node. Set up the custom node value to point to the other node.
  5. Delete the .godot folder if it was present from an earlier run.
  6. Export the Godot project in release configuration. Run the binary and observe that the Rust library panics at unwrapping the empty reference value.

System information

Reproduced in a clean minimal project with Godot v4.2.1 on Windows, but I saw it in a normal project in v4.3-dev5 and on Linux too. Tried with gdext@e7cc36 (2024-04-15).

To make sure that it's only the Option<Gd<Node>> that doesn't get its value initialized I added another field with a primitive type like #[export] value: i32 set to non-zero value in the project and that indeed prints its proper value.

Expected output

(From a release build where debug build was also present.)

PS C:\Users\lostlont\Desktop\godot-rust-test\build\windows\release> .\godot-rust-test.exe
PS C:\Users\lostlont\Desktop\godot-rust-test\build\windows\release> Initialize godot-rust (API v4.2.stable.official, runtime v4.2.1.stable.official)
Godot Engine v4.2.1.stable.official.b09f793f5 - https://godotengine.org
Vulkan API 1.3.260 - Forward+ - Using Vulkan Device #0: AMD - Radeon (TM) RX 470 Graphics

value: 42
other.name: TestNode2
value: 43
other.name: TestNode

Actual output

PS C:\Users\lostlont\Desktop\godot-rust-test\build\windows\release> .\godot-rust-test.exe
PS C:\Users\lostlont\Desktop\godot-rust-test\build\windows\release> Initialize godot-rust (API v4.2.stable.official, runtime v4.2.1.stable.official)
Godot Engine v4.2.1.stable.official.b09f793f5 - https://godotengine.org
Vulkan API 1.3.260 - Forward+ - Using Vulkan Device #0: AMD - Radeon (TM) RX 470 Graphics

value: 42
thread '<unnamed>' panicked at src\lib.rs:43:14:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0:     0x7ffb13af97aa - std::backtrace_rs::backtrace::dbghelp::trace::hacfb2290d6f041d8
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\..\..\backtrace\src\backtrace/dbghelp.rs:131:5
   1:     0x7ffb13af97aa - std::backtrace_rs::backtrace::trace_unsynchronized::hdfe81743a1a02ed5
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\..\..\backtrace\src\backtrace/mod.rs:66:5
   2:     0x7ffb13af97aa - std::sys_common::backtrace::_print_fmt::h7ba8ff6eb3450b74
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\sys_common/backtrace.rs:68:5
   3:     0x7ffb13af97aa - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h419f3866c85fe1bf
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\sys_common/backtrace.rs:44:22
   4:     0x7ffb13b489ad - core::fmt::rt::Argument::fmt::hefb4ad2f61213328
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src\fmt/rt.rs:142:9
   5:     0x7ffb13b489ad - core::fmt::write::h81c90b6a84eba5be
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src\fmt/mod.rs:1120:17
   6:     0x7ffb13aefbdd - std::io::Write::write_fmt::h216459b0e40bea5d
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\io/mod.rs:1846:15
   7:     0x7ffb13af95d3 - std::sys_common::backtrace::_print::h4508c4e8cc70e1aa
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\sys_common/backtrace.rs:47:5
   8:     0x7ffb13af95d3 - std::sys_common::backtrace::print::hea1734d8b31113d5
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\sys_common/backtrace.rs:34:9
   9:     0x7ffb13afc309 - std::panicking::default_hook::{{closure}}::ha8fd0cbe9cc21e6f
  10:     0x7ffb13afc008 - std::panicking::default_hook::hd35fa15eba4e74a2
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src/panicking.rs:292:9
  11:     0x7ffb13afca0f - <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call::ha685e7d47afbfbfb
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\alloc\src/boxed.rs:2029:9
  12:     0x7ffb13afca0f - std::panicking::rust_panic_with_hook::hca0c0de800db3c83
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src/panicking.rs:785:13
  13:     0x7ffb13afc881 - std::panicking::begin_panic_handler::{{closure}}::he773c37bd73058bd
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src/panicking.rs:651:13
  14:     0x7ffb13af9f49 - std::sys_common::backtrace::__rust_end_short_backtrace::hff55a16a8c27989e
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\sys_common/backtrace.rs:171:18
  15:     0x7ffb13afc606 - rust_begin_unwind
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src/panicking.rs:647:5
  16:     0x7ffb13b44fb7 - core::panicking::panic_fmt::h678ed93bf965ebf9
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src/panicking.rs:72:14
  17:     0x7ffb13b45072 - core::panicking::panic::h7b26555fedc35695
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src/panicking.rs:144:5
  18:     0x7ffb13b44ce8 - core::option::unwrap_failed::heba8ea2599e810c6
                               at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src/option.rs:1978:5
  19:     0x7ffb1305ea75 - <godot_rust_test::TestNode as godot_core::obj::traits::cap::ImplementsGodotVirtual>::__virtual_call::function::h5a4012fbff537f2d
  20:     0x7ff75d5d07c4 - <unknown>
  21:     0x7ff75b521c34 - <unknown>
  22:     0x7ff75b521be4 - <unknown>
  23:     0x7ff75b556cbe - <unknown>
  24:     0x7ff75a804336 - <unknown>
  25:     0x7ff75dd0ab23 - <unknown>
  26:     0x7ff75a7c12ee - <unknown>
  27:     0x7ff75a7c13e6 - <unknown>
  28:     0x7ffbce707344 - <unknown>
  29:     0x7ffbcf3426b1 - <unknown>
fatal runtime error: failed to initiate panic, error 5

Note that the actual dll copied to the exported folder is the proper release configuration library. It just looks like that references are not initialized when the debug library is not present.

I have the feeling that it's expected to have a debug build of the godot-rust library always, as opening the project in the editor also shows missing components without it, however the export itself seem to be capable of handling the types and primitives of the library so I'd think that it's just malfunctioning right now. Also this may not be a normal use case in the editor, but in CI build pipelines it would be normal to have only a release build job, without any debug build artifacts.

Thank you very much

Bromeon commented 3 months ago

Thanks for reporting and the detailed description!

Also this may not be a normal use case in the editor, but in CI build pipelines it would be normal to have only a release build job, without any debug build artifacts.

Note that we currently do have a CI run that checks a Rust release build (cargo build --release) and uses a Godot release (non-editor) binary:

https://github.com/godot-rust/gdext/blob/e7cc362aa5285581fc061a02a9b86d42b2cab0a9/.github/workflows/full-ci.yml#L293-L298

And there is also Option<Gd<T>> used, with custom types:

https://github.com/godot-rust/gdext/blob/0b31e79abfb286aa58312304f0dc89aaadec4530/itest/rust/src/object_tests/property_test.rs#L374-L383

However, we don't involve the editor here. Does your problem only appear if you set an object from the editor, and then run it? Not if you set it programmatically?

If yes, could you show the persisted scene file (with the other node attached) in both Release/Debug?

lostlont commented 3 months ago

I assume that it will only appear if I set the reference in the editor, as the nodes themselves are functioning properly so I could probably set any reference to any other node at run-time. I'll try to check this later though.

Here's the scene file I used:

[gd_scene format=3 uid="uid://vmll78trsph2"]

[node name="Node3D" type="Node3D"]

[node name="TestNode" type="TestNode" parent="." node_paths=PackedStringArray("other")]
value = 42
other = NodePath("../TestNode2")

[node name="TestNode2" type="TestNode" parent="." node_paths=PackedStringArray("other")]
value = 43
other = NodePath("../TestNode")

I tried it in the editor manually and from the command line too with godot --headless --verbose --export-release windows ../build/windows/release/godot-rust-test.exe and it produces the same issue. I haven't tried it just by running a Godot project via the Godot engine manually as I can't see any command line options to run instantly in release mode.

I checked your CI script and if I understand it properly then the sed -i'.bak' "s!/debug/!/release/!g" "$dir/rust.gdextension" line in the check-example.sh file actually just replaces the /debug/ folder paths to release paths in the debug library references so each architecture will have both a debug and a release config pointing to the same release library. I tried running my project with a similar gdextension setup and it works in that case. So having a debug config pointing to a release library makes everything run properly. But having separate debug and release file paths and missing the debug library causes the issue in the release build.