Open tommyZZM opened 2 months ago
exactly what godot version are you using, and what platform are you running on? i also notice you've enabled experimental-wasm
, is this necessary?
godot version
Latest godot master
branch these days. recently tried 475248d99df89fc29032a42f1d29ad4cef49c8b5
i also notice you've enabled
experimental-wasm
, is this necessary
It is not necessary.
i was removed experimental-wasm
in the case. same issue happen.
https://github.com/godot-rust/gdext/blob/master/godot-core/src/registry/callbacks.rs#L67
fn create_rust_part_for_existing_godot_part<T, F>(
make_user_instance: F,
base_ptr: sys::GDExtensionObjectPtr,
) -> sys::GDExtensionClassInstancePtr
where
T: GodotClass,
F: FnOnce(Base<T::Base>) -> T,
{
let class_name = T::class_name();
//out!("create callback: {}", class_name.backing);
let base = unsafe { Base::from_sys(base_ptr) }; // <--- base_ptr
https://github.com/godot-rust/gdext/blob/master/godot-core/src/obj/raw.rs#L426C66-L426C80
unsafe fn resolve_instance_ptr(&self) -> sys::GDExtensionClassInstancePtr {
if self.is_null() {
return ptr::null_mut();
}
let callbacks = crate::storage::nop_instance_callbacks();
let token = sys::get_library() as *mut std::ffi::c_void;
let binding = interface_fn!(object_get_instance_binding)(self.obj_sys(), token, &callbacks); // self.obj_sys()
base_ptr
and self.obj_sys()
has a same address on common build godot.
but they have a different address in double-precision case
Update the title... this issue is cause by the api-custom
feature..
even i just add api-custom
the case crash too
That's weird, we build against Godot master in CI, so this should be tested. What os are you on?
Windows 10
even i only just add
api-custom
the case crash too[...]
Maybe a minial reproduce case for this issue is here
You mentioned just having the feature enabled reproduces it, however your example includes EditorPlugin etc.
Can you come up with a truly minimal, reproducible example? If possible, post it inline here.
Also, make sure you create a fresh Godot 4.2.2 project (with GODOT4_BIN
pointing to it).
Godot 4.2.2
I tried to build a 4.2.2 rev of godot (15073afe3856abd2aa1622492fe50026c7d63dc1
). But gdext master prompts error
[print_error] [panic]
gdext was compiled against newer Godot version: v4.3.beta.custom_build
but loaded by older Godot binary, with version: v4.2.2.stable.custom_build
But when I build the latest master branch(8a6c1e8f5232ff3b3a5eac024d590e7479b29e90
), gdext currently doesn't seem to load correctly.
This issues is probably caused by some version difference.
I think it might have something related to prebuilt? what can I do to fix this? can I make custom prebuilts?
Well, you cannot use a newer Godot version in api-custom
than the binary in which you run the extension.
See https://godot-rust.github.io/book/toolchain/godot-version.html and https://godot-rust.github.io/book/toolchain/compatibility.html.
When I want to build a double-precision godot, which commit rev should I build?
I tried adding the api-4-2-2
feature, features = ["api-4-2-2", "api-custom", "double-precision"]
godot 4.2.2 15073afe3856abd2aa1622492fe50026c7d63dc1
and latest gdext master rev cd31a83d80edc7529ab2ef450d4c59d983913c19
But after building and running, it still prompts error
[print_error] Rust function panicked at godot-ffi\src\compat\compat_4_1plus.rs:97.
Context: error when loading GDExtension library
[print_error] [panic]
gdext was compiled against newer Godot version: v4.3.beta.custom_build
but loaded by older Godot binary, with version: v4.2.2.stable.custom_build
Did you read my links? :wink:
You need api-custom
when you use double-precision
. You must make sure that the Godot binary you have in GODOT4_BIN
is compatible with the one you use to run the extension.
@tommyZZM any update?
@tommyZZM any update?
i tried to build a godot 4.3 beta2
https://godotengine.org/article/dev-snapshot-godot-4-3-beta-2/#changelog
(https://github.com/godotengine/godot/commit/b75f0485ba15951b87f1d9a2d8dd0fcd55e178e4)
scons platform=windows
same crash still happen. what is latest compatible godot version or revision for api-custom
and double-precision
build?
Can you come up with a truly minimal, reproducible example? If possible, post it inline here.
Please do this. To avoid further back-and-forth, what I'm looking for is:
lib.rs
file that is self-contained and triggers the problemmaster
, but maybe post commit SHA hashes)Sorry if this sounds annoying, but the reason why I ask is that we have a CI job that runs on Windows with a Godot double configuration (from nightly master), and it just passed a few minutes ago. We definitely use Gd::bind()
(in fact we run the whole integration test suite), and it doesn't crash.
I need a way to reproduce this reliably and with as minimal setup as possible for the issue to stay open. Thanks a lot!
Can you come up with a truly minimal, reproducible example? If possible, post it inline here.
Please do this. To avoid further back-and-forth, what I'm looking for is:
- A single
lib.rs
file that is self-contained and triggers the problem- The exact Cargo commands you use to build
- The exact gdext and Godot versions (ideally both
master
, but maybe post commit SHA hashes)- If there is any configuration or project/scene setup on Godot side necessary to trigger that, elaborate that.
Sorry if this sounds annoying, but the reason why I ask is that we have a CI job that runs on Windows with a Godot double configuration (from nightly master), and it just passed a few minutes ago. We definitely use
Gd::bind()
(in fact we run the whole integration test suite), and it doesn't crash.I need a way to reproduce this reliably and with as minimal setup as possible for the issue to stay open. Thanks a lot!
Hello,
I have tried some examples, and I attempted to run the try_case and bind methods in the enter_tree of both Parent and Child nodes. It seems to work during runtime.
However, the same issue still appears in the example I initially provided. It might be that this problem only occurs with EditorInspectorPlugin, or it could be related to the editor itself.
use godot::prelude::*;
use godot::classes::{
Node,
INode,
EditorInspectorPlugin,
EditorPlugin,
EditorProperty,
IEditorInspectorPlugin,
IEditorPlugin
};
struct IssueReproduceExtensionLibrary;
#[gdextension]
unsafe impl ExtensionLibrary for IssueReproduceExtensionLibrary {}
#[derive(GodotClass)]
#[class(base=Node)]
pub struct MyNodeParent {
pub base: Base<Node>,
pub count: i32,
}
#[godot_api]
impl INode for MyNodeParent {
// in editor created
fn init(base: Base<Node>) -> Self {
// godot_print!("init.. {}", !randInt!());
godot_print!("init..");
MyNodeParent {
base,
count: 1
}
}
fn enter_tree(&mut self) {
godot_print!("enter_tree..");
let child = Gd::from_init_fn(|base| {
MyNodeChild { base }
});
self.base_mut().add_child(child.upcast());
}
}
#[godot_api]
impl MyNodeParent {
#[func]
fn add(&mut self) {
godot_print!("add...");
self.count = self.count + 1
}
}
#[derive(GodotClass)]
#[class(base=Node)]
pub struct MyNodeChild {
pub base: Base<Node>
}
#[godot_api]
impl INode for MyNodeChild {
// in editor created
fn init(base: Base<Node>) -> Self {
// godot_print!("init.. {}", !randInt!());
godot_print!("init..");
MyNodeChild {
base
}
}
fn enter_tree(&mut self) {
let p = self.base_mut().get_parent().unwrap();
let p_class: String = p.clone().get_class().to_string();
godot_print!("[MyNodeChild]enter_tree.. parent is {}", p_class);
if p_class == "MyNodeParent" {
if let Ok(mut p_casted) = p.clone().try_cast::<MyNodeParent>() { // <-- this is OK
let mut b = p_casted.bind_mut();
b.add();
godot_print!("size is {}", b.count)
}
} else {
}
}
}
#[derive(GodotClass)]
#[class(tool, init, editor_plugin, base=EditorPlugin)]
pub struct MyEditorPlugin {
base: Base<EditorPlugin>,
inspector_: Option<Gd<EditorInspectorPlugin>>
}
#[godot_api]
impl IEditorPlugin for MyEditorPlugin {
fn enter_tree(&mut self) {
godot_print!("enter_tree");
// Perform typical plugin operations here.
let inspector_ = Gd::from_init_fn(|base| {
MyEdtiorInspectorPlugin {
base
}
}).clone();
self.inspector_ = Some(inspector_.clone().upcast());
self.base_mut().add_inspector_plugin(inspector_.clone().upcast());
}
fn exit_tree(&mut self) {
// Perform typical plugin operations here.
if let Some(ins) = self.inspector_.clone() {
self.base_mut().remove_inspector_plugin(ins.clone())
} else {
}
}
}
#[derive(GodotClass)]
#[class(tool, init, base=EditorInspectorPlugin)]
pub struct MyEdtiorInspectorPlugin{
base: Base<EditorInspectorPlugin>,
}
#[godot_api]
impl IEditorInspectorPlugin for MyEdtiorInspectorPlugin {
fn can_handle(&self, object: Gd<godot::classes::Object>) -> bool {
let a: String = object.clone().get_class().to_string();
let bool = a == "MyNodeParent";
bool
}
fn parse_begin(&mut self, object: Gd<godot::classes::Object>,) {
let a: String = object.clone().get_class().to_string();
godot_print!("get_calss is {}", a);
if let Ok(mut my_node_parent) = object.clone().try_cast::<MyNodeParent>() {
godot_print!("cast ok {}", a);
let my_node_parent_bind_mut = my_node_parent.bind(); // <-- error this line
// ERROR: godot-rust function call failed: MyEdtiorInspectorPlugin::parse_begin()
// Reason: [panic] Class test_case::MyNodeParent -- null instance; does the class h?
godot_print!("size is {}", my_node_parent_bind_mut.count) // <-- crash this line
}
}
}
In the parse_begin method of EditorInspectorPlugin, when using custom-api, the object parameter seems unable to be correctly cast to the original object, resulting in a panic when calling bind. I tried printing the class name of the object, and it appears to be correct.
ERROR: godot-rust function call failed: MyEdtiorInspectorPlugin::parse_begin()
Reason: [panic] Class test_case::MyNode -- null instance; does the class have a Godot creator function?
at: godot_core::private::report_call_error (godot-core\src\private.rs:313)
this should be the minial case yet
It doesn’t crash like the Mesh object does, but the console outputs a panic when the bind method is executed during the parse_begin
.
To reproduce the panic, you have to select the MyNode
in godot editor to trigger it.
use godot::prelude::*;
use godot::classes::{
Node,
INode,
EditorInspectorPlugin,
EditorPlugin,
EditorProperty,
IEditorInspectorPlugin,
IEditorPlugin
};
struct IssueReproduceExtensionLibrary;
#[gdextension]
unsafe impl ExtensionLibrary for IssueReproduceExtensionLibrary {}
#[derive(GodotClass)]
#[class(base=Node)]
pub struct MyNode {
pub base: Base<Node>,
#[export]
size: i32,
}
#[godot_api]
impl INode for MyNode {
// in editor created
fn init(base: Base<Node>) -> Self {
// godot_print!("init.. {}", !randInt!());
godot_print!("init..");
MyNode {
base,
size: 1024
}
}
}
#[derive(GodotClass)]
#[class(tool, init, editor_plugin, base=EditorPlugin)]
pub struct MyEditorPlugin {
base: Base<EditorPlugin>,
inspector_1: Option<Gd<EditorInspectorPlugin>>
}
#[godot_api]
impl IEditorPlugin for MyEditorPlugin {
fn enter_tree(&mut self) {
// Perform typical plugin operations here.
let inspector_1 = Gd::from_init_fn(|base| {
MyEdtiorInspectorPlugin {
base
}
}).clone();
self.inspector_1 = Some(inspector_1.clone().upcast());
self.base_mut().add_inspector_plugin(inspector_1.clone().upcast());
}
fn exit_tree(&mut self) {
// Perform typical plugin operations here.
if let Some(ins) = self.inspector_1.clone() {
self.base_mut().remove_inspector_plugin(ins.clone())
} else {
}
}
}
#[derive(GodotClass)]
#[class(tool, init, base=EditorInspectorPlugin)]
pub struct MyEdtiorInspectorPlugin{
base: Base<EditorInspectorPlugin>,
}
#[godot_api]
impl IEditorInspectorPlugin for MyEdtiorInspectorPlugin {
fn can_handle(&self, object: Gd<godot::classes::Object>) -> bool {
let a: String = object.get_class().to_string();
let bool = a == "MyNode";
bool
}
// panic when you select `MyNode` in editor
fn parse_begin(&mut self, object: Gd<godot::classes::Object>,) {
if let Ok(mesh) = object.try_cast::<MyNode>() {
// mesh.bind().size
// ERROR: godot-rust function call failed: MyEdtiorInspectorPlugin::parse_begin()
// Reason: [panic] Class test_case::MyNode -- null instance; does the class have a Godot creator function?
// at: godot_core::private::report_call_error (godot-core\src\private.rs:313)
godot_print!("size is {}", mesh.bind().size) // <-- crash this line
}
}
}
To reproduce the issue:
You can use the repository I initially provided to follow these steps. https://github.com/tommyZZM/issue-cast-gd-pointer-crash-in-double-build
case yet find in EditorInspectorPlugin
interacts with try_cast
and bind
in its callbacks
Thanks a lot. Since this is a bit more involved, it will take me some time until I can get around to try and reproduce it. In case you find a simpler way in the meantime (e.g. code only), let me know :slightly_smiling_face:
I m trying to write a custom plugin for godot in double precision buildGd.bind() cause crash, with double-precision feature in (Latest godotdouble precision
build godot.master
branch)Update the title... this issue is cause by the api-custom feature..
even i only just add
api-custom
the case crash tooGd.bind() cause crash, with
api-custom
feature in custom build godot...But if same codes run in common build version it works fine
Maybe a minial reproduce case for this issue is here
https://github.com/tommyZZM/issue-cast-gd-pointer-crash-in-double-build/blob/main/rust/src/lib.rs#L95
logs