GNOME Bugzilla – Bug 776092
Assertion in simple GLib.Variant usage
Last modified: 2016-12-22 07:33:44 UTC
Maybe my usage of GLib.Variant is too naive here, but I can trivially cause a critical assertion by running the following: $ python3 -c 'from gi.repository import GLib; v = GLib.Variant("s", "foo")' (process:27857): GLib-CRITICAL **: g_hash_table_destroy: assertion 'hash_table != NULL' failed (process:27857): GLib-CRITICAL **: g_hash_table_destroy: assertion 'hash_table != NULL' failed Exception ignored in: Interestingly, if I build pygobject against python2 (or use my distro's package), I don't see this assertion. I suppose this comes from the explicit unref in Variant's __del__, but I don't understand what happens exactly. I can avoid this issue by deleting v before exit or sinking the ref (I guess really just taking another ref since pygobject does sink the ref and is_floating() tells me it's not). Anyway, here's the backtrace: (gdb) r Starting program: /usr/bin/python3 -c from\ gi.repository\ import\ GLib\;\ v\ =\ GLib.Variant\(\"s\",\ \"foo\"\) [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". (process:28487): GLib-CRITICAL **: g_hash_table_destroy: assertion 'hash_table != NULL' failed Program received signal SIGTRAP, Trace/breakpoint trap. _g_log_abort (breakpoint=breakpoint@entry=1) at /usr/src/packages/BUILD/glib2.0-2.50.2+dev22.0cb2266/./glib/gmessages.c:487 487 /usr/src/packages/BUILD/glib2.0-2.50.2+dev22.0cb2266/./glib/gmessages.c: No such file or directory. (gdb) bt
+ Trace 236979
I should mention that when I use GLib.Variant in a real program, I don't see this problem. It really only happens if I exit immediately after creating the variant and storing it in a variable.
Created attachment 342345 [details] [review] Handle multiple deinit of callable cache In python3, it seems that the callable cache deinit can be called multiple times when the program is exiting. Make that safer by clearing the various pointers in the structure using g_clear_pointer and Py_CLEAR. A subsequent call will skip all the deinit by seeing NULL pointers for the members. This was causing a critical warning when destroying the arg name hash table multiple times with the following trivial program: $ python3 -c 'from gi.repository import GLib; v = GLib.Variant("s", "foo")' (process:32378): GLib-CRITICAL **: g_hash_table_destroy: assertion 'hash_table != NULL' failed (process:32378): GLib-CRITICAL **: g_hash_table_destroy: assertion 'hash_table != NULL' failed
Created attachment 342346 [details] [review] Handle exception unreffing Variant at exit Calling unref will cause gi and gi.repository.GLib to be imported. However, if the program is exiting, then these modules have likely been removed from sys.modules and will raise an exception. Assume that's the case for ImportError and ignore the exception since everything will be cleaned up, anyways. This can be triggered with the following trivial program: $ python3 -c 'from gi.repository import GLib; v = GLib.Variant("s", "foo")' Exception ignored in: Adding some debug code to show the full exception revealed this: Traceback (most recent call last):
+ Trace 237007
self.unref()
These 2 patches fix things for me. I'm pretty sure they're right, and I ran this on some other pygi scripts I had around. The test suite still passes for me. That said, it's dealing with some internals of pygobject that I'm not really familiar with.
Review of attachment 342345 [details] [review]: Looks good, thanks. Pushed as: https://git.gnome.org/browse/pygobject/commit/?id=54c623ba6396
The following fixes have been pushed:
https://git.gnome.org/browse/pygobject/commit/?id=8694e4dd4