Got assert() error for Nim version of GST basic tutorial

Testing upcomming v0.7.8 Nim GTK bindings I just got an assert error.

Problem seems to be gst_parse_launch(). It is reported by gobject-introspection as not a constructor, returning a floating object with transfer none.

That combination is really strange, I never got that before, so the assert().

/**
 * gst_parse_launch:
 * @pipeline_description: the command line describing the pipeline
 * @error: the error message in case of an erroneous pipeline.
 *
 * Create a new pipeline based on command line syntax.
 * Please note that you might get a return value that is not %NULL even though
 * the @error is set. In this case there was a recoverable parsing error and you
 * can try to play the pipeline.
 *
 * To create a sub-pipeline (bin) for embedding into an existing pipeline
 * use gst_parse_bin_from_description().
 *
 * Returns: (transfer floating) (nullable): a new element on success, %NULL on
 *   failure. If more than one toplevel element is specified by the
 *   @pipeline_description, all elements are put into a #GstPipeline, which
 *   than is returned.
 */
GstElement *
gst_parse_launch (const gchar * pipeline_description, GError ** error)
{
  return gst_parse_launch_full (pipeline_description, NULL, GST_PARSE_FLAG_NONE,
      error);
}

My guess is that “Returns: (transfer floating)” is invalid.

https://gstreamer.freedesktop.org/documentation/gstreamer/gstparse.html?gi-language=c#gst_parse_launch

No, it is not a bug: transfer floating is valid from

https://wiki.gnome.org/Projects/GObjectIntrospection/Annotations

" alias for none , can be used for floating objects."

Will remove the assert() statement for now and investigate later in more detail.

This is intentional and indeed very confusing, and the source of bugs in many bindings. As are floating references in general.

I don’t know how much you know about floating reference handling in bindings, so I’ll just shortly re-iterate the basic rules. The GObject docs about floating references contain a bit more about it but maybe not too clear.

  1. Never ever have floating references in the bindings (* exceptions below) and especially don’t expose any API for them in the bindings
  2. Always sink floating references immediately when you receive one in a transfer none context. As you noticed, transfer floating is an alias for that which only shows up in the code but not in the .gir or anywhere else. The basic idea is: transfer none return value => call g_object_ref() on it immediately if it’s a normal GObject, or g_object_ref_sink() if it’s something inheriting from GInitiallyUnowned
    2.1 This includes constructors btw, note that their return value is transfer none in the .gir for GInitiallyUnowned subclasses
  3. If you get a floating reference in a transfer full context then you’re going to have fun and need to very carefully handle them. This shouldn’t really happen in well-behaved code but unfortunately not everything is perfect. (exception 1)
  4. If you get a floating reference in a transfer none context via a parameter to a callback, signal handler, vfunc (all the same really), then don’t sink it and make sure to keep it floating or otherwise you will steal the floating reference from the caller. In Rust-terms: the callback borrows the parameters (and depending on how Nim does memory management this leaves the opportunity to not create copies or increase the reference count here although it’s a transfer none context). This is especially interesting in vfuncs like GObject::set_property() and GObject::constructed() which are called before anything ever had the opportunity to sink the floating reference, and you really want to make sure that if you subclass a GInitiallyUnowned that it is properly floating when coming out of g_object_new(). (exception 2)
  5. The return value of g_object_new() is transfer full for normal GObjects and transfer none for anything inheriting from GInitiallyUnowned. I.e. in case of the latter you call g_object_ref_sink() on it.
  6. Be prepared to run into various bugs in how C libraries handle floating references and interesting corner cases you didn’t handle correctly in your bindings.

Feel free to ask more questions here if something is not clear :slight_smile:

Thank you very much for your reply Mr Droege. Indeed I have seen that you are working on GST issue tracker, if I remember correctly you are working for Rust.

I will read your fine reply tomorrow more carefully.

Yes, the fact that the returned object of gst_parse_launch() is floating and at the same time the transfer is of type “none” was surprising for me, so I thought it was an error and I was already going to send a issue to Gst issue tracker. But I have learned that it is intended, and I think I can live with that fact.

I think the Nim bindings work not bad with floating references in general, we call g_object_ref_sink when ever we get a floating reference to take ownership. That was suggested by Mr Bassi and simplifies things, we use toggle references and the Nim GC unref the GObjects when the Nim proxy object goes out of scope. Current bindings v0.7.7 have a little bug, g_object_ref_sink() is called also on non floating objects with transfer type full, resulting in memory leaks. I am going to fix that. Since some months we have the new ARC deterministic memory management available for Nim, that makes detecting errors more easy. The traditional Nim GC had a delay in freeing memory, which makes discovering errors more difficult.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.