After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 662383 - (skip) return values cause SystemError: error return without exception set
(skip) return values cause SystemError: error return without exception set
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: introspection
3.0.x
Other Linux
: Normal normal
: ---
Assigned To: Martin Pitt
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2011-10-21 12:02 UTC by Martin Pitt
Modified: 2011-10-21 15:51 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
reproducer (643 bytes, text/x-python)
2011-10-21 12:02 UTC, Martin Pitt
  Details
test case (725 bytes, patch)
2011-10-21 14:22 UTC, Martin Pitt
none Details | Review
test case (732 bytes, patch)
2011-10-21 14:38 UTC, Martin Pitt
none Details | Review
Fix "Returns: (skip)" method calls without (out) arguments (2.08 KB, patch)
2011-10-21 15:34 UTC, Martin Pitt
none Details | Review
Fix "Returns: (skip)" method calls without (out) arguments (2.08 KB, patch)
2011-10-21 15:37 UTC, Martin Pitt
none Details | Review
Fix "Returns: (skip)" method calls without (out) arguments (2.08 KB, patch)
2011-10-21 15:38 UTC, Martin Pitt
none Details | Review
Fix "Returns: (skip)" method calls without (out) arguments (2.22 KB, patch)
2011-10-21 15:47 UTC, Martin Pitt
committed Details | Review

Description Martin Pitt 2011-10-21 12:02:41 UTC
Created attachment 199629 [details]
reproducer

I'm currently writing a test suite for udisks2, which is using gdbus-codegen to generate the libudisks library. I noticed that many calls fail like

Traceback (most recent call last):
  • File "/home/martin/udisks2test", line 487 in test_btrfs
    self._do_fs_check('btrfs')
  • File "/home/martin/udisks2test", line 632 in _do_fs_check
    self._do_udisks_check(type)
  • File "/home/martin/udisks2test", line 694 in _do_udisks_check
    self.fs_create(None, type, options)
  • File "/home/martin/udisks2test", line 284 in fs_create
    block.call_create_filesystem_sync(type, options, None)
  • File "/usr/lib/python3/dist-packages/gi/types.py", line 43 in function
    return info.invoke(*args, **kwargs)
SystemError: error return without exception set

I isolated this into a small test script which calls call_mount_sync()/call_umount_sync() on a block device through udisks2:

$ GI_TYPELIB_PATH=udisks LD_LIBRARY_PATH=udisks/.libs python ~/test.py /dev/sdb calling through gdbus-codegen glue
Traceback (most recent call last):
  File "/home/martin/test.py", line 23, in <module>
    fs.call_unmount_sync(GLib.Variant('a{sv}', {}), None)
  File "/usr/lib/python2.7/dist-packages/gi/types.py", line 43, in function
    return info.invoke(*args, **kwargs)
SystemError: error return without exception set

This crashes in

      fs.call_unmount_sync(GLib.Variant('a{sv}', {}), None)

However, when I don't use the generated call_XX_sync() wrapper, and instead use the GDBuxProxy object directly (through the pygobject overrides), it works fine:

    fs.Unmount(('(a{sv})'), {})

This makes me believe that there is a bug somewhere in gdbus-codegen-generated glue code which returns the wrong return boolean in some cases?

This is with glib 2.30.0.
Comment 1 Martin Pitt 2011-10-21 12:04:02 UTC
Oh, forgot to mention: If you call the test script with just one argument (block device), it uses the gdbus-codegen glue. If you specify a second one, it uses the GDBuxProxy.call_sync() method, which works.
Comment 2 Martin Pitt 2011-10-21 12:24:32 UTC
On second look, I peeked into udisks_filesystem_call_unmount_sync(), and the return code seems alright, and changing it doesn't even make a difference. error is properly initialized and *error == NULL, so there was no exception.

The SystemError is raised in python itself, in ./Python/ceval.c. However, I'm afraid I don't understand ceval.c at all, so I can't say what it's complaining about. So this might not be a glib bug after all.
Comment 3 Martin Pitt 2011-10-21 13:08:53 UTC
The Google sphere is full with similarly ominous errors in other programs. Common that I saw in more than just one place are: 

(1) it looks related to multi-threaded programs. I think the call_sync stuff presumably sets up a local main loop somewhere, which might set off a separate thread. Anyway, adding GLib.threads_init() doesn't change things.

(2) many, if not all reports say that this is probably due to a broken python extension, which would be pygobject in this case.
Comment 4 David Zeuthen (not reading bugmail) 2011-10-21 13:31:02 UTC
(In reply to comment #3)
> (1) it looks related to multi-threaded programs. I think the call_sync stuff
> presumably sets up a local main loop somewhere, which might set off a separate
> thread. Anyway, adding GLib.threads_init() doesn't change things.

Yeah, it ends up calling g_dbus_connection_send_message_with_reply_sync() that sets up its own private GMainContext, passes work to the (private) GDBus worker thread and then sits in the main-loop waiting for completion from the worker thread. But all this is an implementation detail - the key thing is that it simply blocks the calling thread until a reply is received (or until the timeout is reached).
Comment 5 Martin Pitt 2011-10-21 13:37:02 UTC
I confirm that dropping the (skip) from

 * Returns: (skip): %TRUE if the call succeded, %FALSE if @error is set.

indeed fixes this, i. e. pygobject is expecting that error flag but doesn't get it. When I simply remove that from udisks-generated.c and rebuild, the example works perfectly.
Comment 6 Martin Pitt 2011-10-21 14:22:44 UTC
Created attachment 199646 [details] [review]
test case

This only happens if the method has no other (out) arguments, which is why the existing regress_test_obj_skip_return_val() test case did not catch it.

I added a new test case without (out) arguments:

http://git.gnome.org/browse/gobject-introspection/commit/?id=d6ab510feb72ac0ff30f0942e874e2d52f3e82f6

With that, a reproducer is trivial, attaching patch against pygobject which adds it to the test suite.
Comment 7 Martin Pitt 2011-10-21 14:38:09 UTC
Created attachment 199647 [details] [review]
test case

this time with correct test case name
Comment 8 Martin Pitt 2011-10-21 15:34:06 UTC
Created attachment 199659 [details] [review]
Fix "Returns: (skip)" method calls without (out) arguments

This is the bug fix including the test case.
Comment 9 Martin Pitt 2011-10-21 15:37:06 UTC
Created attachment 199660 [details] [review]
Fix "Returns: (skip)" method calls without (out) arguments

Whoops, I had the test case part for real exception raising commented out for debugging. This re-enables it.
Comment 10 Martin Pitt 2011-10-21 15:38:16 UTC
Created attachment 199661 [details] [review]
Fix "Returns: (skip)" method calls without (out) arguments

Erk, third time is the charm!
Comment 11 Martin Pitt 2011-10-21 15:47:39 UTC
Created attachment 199663 [details] [review]
Fix "Returns: (skip)" method calls without (out) arguments

This is a stronger version of the patch which now asserts our logic. I. e. if we do not have any (out) arguments and a skipped return value, we don't ask whether our current py_return is NULL, but assert it, to catch bad (future?) code paths where we would unexpectedly have an existing return value.
Comment 12 Martin Pitt 2011-10-21 15:51:38 UTC
Comment on attachment 199663 [details] [review]
Fix "Returns: (skip)" method calls without (out) arguments

Discussed with Tomeu on IRC, he acked. Committed to master.