GNOME Bugzilla – Bug 691753
segfault on methods returning GValues of type GValue and no value
Last modified: 2018-01-10 20:21:42 UTC
To reproduce: from gi.repository import GObject v = GObject.Value() v2 = GObject.Value(GObject.Value.__gtype__, v)
In particular, this happens for v = GObject.Value() v.init(GObject.TYPE_VALUE) The init() call crashes on a NULL pointer:
+ Trace 231388
here: } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) { GValue *n_value = g_value_get_boxed (value); return pyg_value_as_pyobject(n_value, copy_boxed); (gdb) call g_value_get_boxed(value) $4 = (void *) 0x0 and pyg_value_as_pyobject() does not work with NULL pointers (deliberately).
This code was introduced in commit fe3966c2, for transparently "unpacking" GValues that are returned by functions. We want to keep this behaviour, both for backwards compatibility as well as for convenience (in most cases we don't want to deal with GValue objects in Python). But this crashes as g_type_init() returns a GValue which has a data type, but a NULL v_pointer because it hasn't been set yet.
If a method returns a GValue*, which has a properly set value, then pygobject should continue to transparently unwrap this, as discussed in the previous comment. For handling returned GValues* which are not initialized or initialized without a set value, we can either (1) return (a python wrapper of) the GValue itself, or (2) return None. (1) seems a bit magic to me, as the return type of a method would then depend on the status of the GValue; (2) seems more consistent with what PyGObject does at the moment, but loses some information to the caller, in particular to which gtype the GValue was initialized. By and large, I'm still favoring (2) at the moment, though. Opinions?
I have another idea: Instead of doing the heuristic (1), and the problematic (2) (you'll run into type compatibility issues everywhere, I tried), we could limit this to g_value_init() only. As far as I can see this should be the only (or at least one of the very few) functions which actually return a GValue with a NULL value. So we could just (skip) the return value of g_value_init(); but I have a feeling that the GLib guys might not like that, and indeed other interpreters like JS might not have the same automatic GValue conversion that pygobjejct has. Or we could write a static Python wrapper for g_value_init() in gi/_gobject/ which just returns None.
I got a bit further with this. For the record, g_value_set_boxed() and g_value_get_boxed() also need static overrides as the C API just takes gconstpointers which GI cannot translate to "boxed interface" right now.
Can the methods be annotated as taking a generic "Boxed" as the arg? Also, at some point I think it will be worth exposing raw pointers to Python for the static G types (as a private attribute). This way we can work around needing special case static bindings for anything taking raw pointers and simply use an override instead. For instance: class Value(GObject.Value): def set_boxed(self, boxed): return super().set_boxed(boxed._gptr) That can at least work well for input args which take a gpointer, output args will be more difficult. I have been thinking about this for solving bug 633999 if we cannot annotate signal methods as Object.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/pygobject/issues/41.