-
-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Converting RefCounted to Variant causes premature free #108
Comments
Maybe related: godotengine/godot#64813 |
The discord issue mentioned has a workaround where you just somehow keep a shared reference to the img after returning. Which seems to support the idea that these are related somehow |
Smaller repro that brings us closer to the smoking gun: eprintln!("new()");
let mut image = Image::new();
eprintln!("refcount is now {}", image.get_reference_count());
eprintln!("to_variant()");
let variant = image.to_variant();
eprintln!("refcount is now {}", image.get_reference_count()); Output:
The last one should be 2 of course. |
Thanks for the help with debugging, especially the "smaller repro" in the last comment was very useful to locate the issue. In case you're interested about what exactly went wrong, the PR contains a detailed description. |
Fix confirmed to work in integration tests for #101. Thank you! |
This code results in an unexpected panic:
With
--features=trace
, I see this:Why does
drop()
seewas last=true
? Isn't theVariant
supposed to hold another reference to theImage
object?Maybe related is this report that just came in on Discord:
I did some sleuthing:
object_to_variant
, which is obtained throughget_variant_from_type_constructor
ingdextension_interface.h
.gdextension_get_variant_from_type_constructor
returns a pointer toVariantTypeConstructor<Object *>::variant_from_type
.VariantInitializer<T>::init(variant);
andVariantInternalAccessor<T>::set(variant, *((T *)p_value));
. One by one:VariantInitializer<T>::init(variant);
callsVariantInternal::init_object(v);
.object_assign_null(v);
and then setsv->type = Variant::OBJECT;
.object_assign_null
setsv->_get_obj().obj = nullptr;
andv->_get_obj().id = ObjectID();
. So that's a thing: a non-nil variant that holds a null object.variant_from_type
.VariantInternalAccessor<T>::set(variant, *((T *)p_value));
as mentioned.VariantInternal::object_assign(v, p_value);
.T = Object
so we end up inobject_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere.
.variant_construct.cpp
. Ifo
is ref-counted, it callsinit_ref()
on it. On failure, it sets the variant to a null object.v->_get_obj().obj = const_cast<Object *>(o);
andv->_get_obj().id = o->get_instance_id();
.So what does
init_ref
do, exactly? The documentation is not much help so let's turn to the source again:reference()
.refcount.refval()
, which increments the ref count and returns the new one. Except if the ref count is zero, then it does nothing and returns zero. If that happens,reference()
returnsfalse
.reference()
does some irrelevant stuff with script. Probably to allow an object to be destroyed if the only reference to it is from its script._get_extension()->reference(...)
which may be related to gdextension but I'll ignore it for now._instance_binding_reference(true);
onObject
. I don't understand what it does.true
.Long story short:
init_ref
increments the reference count. Not sure if there's a more complicated purpose here, or if it's just mis-named.The text was updated successfully, but these errors were encountered: