Skip to content

GDExtension Ref<T> object freeing error. #652

@zombietype

Description

@zombietype

Background Info:

Working on adding GDExtension support for Video playback.
One part of the VideoStream is Ref<VideoStreamPlayback> VideoStream::instance_playback()

For the VideoStreamExtension class this is implemented as

Ref<VideoStreamPlayback> VideoStreamExtension::instance_playback() {
	Ref<VideoStreamPlaybackExtension> ref;
	if (GDVIRTUAL_CALL(_instance_playback, ref)) {
		ERR_FAIL_COND_V_MSG(ref.is_null(), nullptr, "Plugin returned null playback");
		// open_file() is an unregistered private method in VideoStreamPlaybackExtension
                ref->open_file(file);  
                // set_audio_track() is a virtual method implemented with GDVIRTUAL_CALL
		ref->set_audio_track(audio_track); 
		return ref;
	}
	return nullptr;
}

On the GDExtension plugin side:

godot::Ref<godot::VideoStreamPlaybackExtension> godot::VideoStreamReference::_instance_playback() {
	Ref<VideoStreamPlaybackReference> ref;
	ref.instantiate();
        // will add the temp fix here.
	return ref;
}

The Issue:

The above implementation crashes with:

Exception thrown: read access violation.
**VideoStreamPlayback::set_audio_track[virtual]** was 0xFFFFFFFFFFFFFFFF.

Stepping through in the debugger shows the VideoStreamPlaybackReference::_cleanup (Destructor) is called on return from

// binder_common.hpp
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
	PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}

As the Ref counts to 0.

If one stores the Ref in the plugin: Godot and the Plugin both has separate 'ownership' of the object. As such after cleanup on one end - the other Ref dangles.

Temporary Solution:

RefCounted* r = static_cast<RefCounted*>(ref.ptr());
r->reference();

Adding this increments the refcount and prevents the deletion after encode.
The Ref quietly deletes and reduces refcount to 1 which is copied and owned by Godot

Works for this particular case since it's an ownership transfer. But it will not work in Shared ownership case as RefCounted object seems to not be shared across the boundary.

Related: #417

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis has been identified as a bugtopic:gdextensionThis relates to the new Godot 4 extension implementation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions