getsolus / PackageKit

A D-BUS abstraction layer that allows the user to manage packages in a secure way using a cross-distro, cross-architecture API.
GNU General Public License v2.0
0 stars 0 forks source link

Segfault when using PkClient GTask, self.percentage() and pisi.api APIs that use the @locked decorator with a pisi.ui.UI override. #14

Closed joebonrichie closed 1 month ago

joebonrichie commented 6 months ago

Since https://github.com/getsolus/PackageKit/commit/b068646d2fbb246c590a47531688c69df2699fa6

We're getting a segfault when we run self.percentage() from our pisi.ui.UI override for pisi APIs that use the @locked decorator.

The pisi locked decorator is here: https://github.com/getsolus/eopkg/blob/python3/pisi/api.py#L39

A simplified version of our code is below

class SimplePisiHandler(pisi.ui.UI):
    def __init__(self, base):
        pisi.ui.UI.__init__(self, False, False)
        # PackageKitPisiBackend
        self.base = base
        def notify(self, event, **keywords):
            if event == installing:
                emit_installing blah blah blah
                self.base.percentage(somenumber)

class PackageKitPisiBackend(PackageKitBaseBackend, PackagekitPackage):
    def __init__(self, args):
        PackageKitBaseBackend.__init__(self, args)
        self.get_db()
        self.saved_ui = pisi.context.ui

    def get_db(self):
        self.componentdb = pisi.db.componentdb.ComponentDB()
        # self.filesdb = pisi.db.filesdb.FilesDB()
        self.installdb = pisi.db.installdb.InstallDB()
        self.packagedb = pisi.db.packagedb.PackageDB()
        self.historydb = pisi.db.historydb.HistoryDB()
        self.repodb = pisi.db.repodb.RepoDB()

    def privileged(func):
        """
        Decorator for synchronizing privileged functions
        """
        def wrapper(self, *__args,**__kw):
            ui = SimplePisiHandler(self)
            pisi.api.set_userinterface(ui)
            try:
                func(self, *__args,**__kw)
            except Exception as e:
                raise(e)
            # FIXME: the first call gets garbled 16:2percentage'entagegeK100: invalid command 'parse:
            self.percentage(100)
            self.percentage(100)
            self.get_db()
            self.finished()
            pisi.api.set_userinterface(self.saved_ui)
        return wrapper

    @privileged
    def install_packages(self, transaction_flags, package_ids):
        pisi.api.install(packages)

When we don't try to emit percentage updates we no longer get a segfault. If we revert https://github.com/getsolus/PackageKit/commit/b068646d2fbb246c590a47531688c69df2699fa6 as a workaround we'll get a (pkcon:7463): GLib-GObject-CRITICAL **: 16:07:48.354: g_object_unref: assertion 'G_IS_OBJECT (object)' failed warning.

Additionally, we have to emit self.percentage(100) twice after finishing as the first call gets garbled up with a ' endix getting added to the self.percentage() call.

Interestingly emitting self.item_progress() updates doesn't result in a segfault only self.percentage()

Note that this segfault only occurs when using pisi APIs that use the @locked decorator. Using something like pisi.api.fetch we can set percentage updates and experience no segfault.

It seems a combination of the @locked decorator that calls pisi.db.invalidate_caches() which invalidates our self.get_db() initialized values and emitting self.percentage() updates is causing the issue.

Backtrace with https://github.com/getsolus/PackageKit/commit/b068646d2fbb246c590a47531688c69df2699fa6

(gdb) bt
#0  g_type_check_instance_is_fundamentally_a (type_instance=type_instance@entry=0x5646812bfe70, fundamental_type=fundamental_type@entry=0x50 [GObject])
    at ../gobject/gtype.c:4153
#1  0x00007f74dfd63d2e in g_object_unref (_object=0x5646812bfe70) at ../gobject/gobject.c:4287
#2  0x00007f74dff3b0a6 in glib_autoptr_clear_GTask (_ptr=0x5646812bfe70) at /usr/include/glib-2.0/gio/gio-autocleanups.h:138
#3  0x00007f74dff3b0c3 in glib_autoptr_cleanup_GTask (_ptr=0x7ffe60ccb280) at /usr/include/glib-2.0/gio/gio-autocleanups.h:138
#4  0x00007f74dff3df0c in pk_task_ready_cb (source_object=0x5646812b4370 [PkTaskText], res=0x5646812c15d0, user_data=0x5646812bfe70)
    at ../lib/packagekit-glib2/pk-task.c:846
#5  0x00007f74dfc1c33c in g_task_return_now (task=task@entry=0x5646812c15d0 [GTask]) at ../gio/gtask.c:1361
#6  0x00007f74dfc1d145 in g_task_return (type=<optimized out>, task=0x5646812c15d0 [GTask]) at ../gio/gtask.c:1430
#7  g_task_return (task=0x5646812c15d0 [GTask], type=<optimized out>) at ../gio/gtask.c:1387
#8  0x00007f74dff0a5a1 in pk_client_state_finish (state=0x5646812c1720 [PkClientState], error=0x0) at ../lib/packagekit-glib2/pk-client.c:245
#9  0x00007f74dff0ce96 in pk_client_signal_finished (state=0x5646812c1720 [PkClientState], exit_enum=PK_EXIT_ENUM_SUCCESS, runtime=7264)
    at ../lib/packagekit-glib2/pk-client.c:1202
#10 0x00007f74dff0d279 in pk_client_signal_cb
    (proxy=0x5646812c1390 [GDBusProxy], sender_name=0x7f74c0009610 ":1.360", signal_name=0x7f74c0008e40 "Finished", parameters=0x7f74c0003b60, user_data=0x5646812b9560) at ../lib/packagekit-glib2/pk-client.c:1284
#15 0x00007f74dfd7a2a0 in <emit signal 'g-signal' on instance 0x5646812c1390 [GDBusProxy]>
    (instance=instance@entry=0x5646812c1390, signal_id=<optimized out>, detail=<optimized out>) at ../gobject/gsignal.c:3583
    #11 0x00007f74dfd5e5fa in g_closure_invoke
    (closure=0x5646812aa800, return_value=0x0, n_param_values=4, param_values=0x7ffe60ccb6c0, invocation_hint=0x7ffe60ccb610)
    at ../gobject/gclosure.c:834
    #12 0x00007f74dfd72b16 in signal_emit_unlocked_R
    (node=node@entry=0x7ffe60ccb7c0, detail=detail@entry=0, instance=instance@entry=0x5646812c1390, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7ffe60ccb6c0) at ../gobject/gsignal.c:3888
    #13 0x00007f74dfd744c2 in signal_emit_valist_unlocked
    (instance=instance@entry=0x5646812c1390, signal_id=signal_id@entry=12, detail=detail@entry=0, var_args=var_args@entry=0x7ffe60ccb930)
    at ../gobject/gsignal.c:3520
    #14 0x00007f74dfd7a1de in g_signal_emit_valist (instance=0x5646812c1390, signal_id=12, detail=0, var_args=0x7ffe60ccb930)
    at ../gobject/gsignal.c:3263
#16 0x00007f74dfc8b205 in on_signal_received
    (connection=<optimized out>, sender_name=0x7f74c0006fb0 ":1.360", object_path=<optimized out>, interface_name=<optimized out>, signal_name=0x7f74c00094f0 "Finished", parameters=0x7f74c0003b60, user_data=0x5646812b0180) at ../gio/gdbusproxy.c:874
#17 0x00007f74dfc77395 in emit_signal_instance_in_idle_cb (data=0x7f74c0009240) at ../gio/gdbusconnection.c:3798
#18 0x00007f74dfe02377 in g_main_dispatch (context=context@entry=0x5646812a1dd0) at ../glib/gmain.c:3344
#19 0x00007f74dfe05677 in g_main_context_dispatch_unlocked (context=0x5646812a1dd0) at ../glib/gmain.c:4152
#20 g_main_context_iterate_unlocked (context=0x5646812a1dd0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>)
    at ../glib/gmain.c:4217
#21 0x00007f74dfe05fd7 in g_main_loop_run (loop=0x5646812a1ff0) at ../glib/gmain.c:4419
#22 0x0000564680126113 in main (argc=3, argv=0x7ffe60ccc008) at ../client/pk-console.c:2400
(gdb) 
#0  g_type_check_instance_is_fundamentally_a (type_instance=type_instance@entry=0x5646812bfe70, fundamental_type=fundamental_type@entry=0x50 [GObject])
    at ../gobject/gtype.c:4153
#1  0x00007f74dfd63d2e in g_object_unref (_object=0x5646812bfe70) at ../gobject/gobject.c:4287
#2  0x00007f74dff3b0a6 in glib_autoptr_clear_GTask (_ptr=0x5646812bfe70) at /usr/include/glib-2.0/gio/gio-autocleanups.h:138
#3  0x00007f74dff3b0c3 in glib_autoptr_cleanup_GTask (_ptr=0x7ffe60ccb280) at /usr/include/glib-2.0/gio/gio-autocleanups.h:138
#4  0x00007f74dff3df0c in pk_task_ready_cb (source_object=0x5646812b4370 [PkTaskText], res=0x5646812c15d0, user_data=0x5646812bfe70)
    at ../lib/packagekit-glib2/pk-task.c:846
#5  0x00007f74dfc1c33c in g_task_return_now (task=task@entry=0x5646812c15d0 [GTask]) at ../gio/gtask.c:1361
#6  0x00007f74dfc1d145 in g_task_return (type=<optimized out>, task=0x5646812c15d0 [GTask]) at ../gio/gtask.c:1430
#7  g_task_return (task=0x5646812c15d0 [GTask], type=<optimized out>) at ../gio/gtask.c:1387
#8  0x00007f74dff0a5a1 in pk_client_state_finish (state=0x5646812c1720 [PkClientState], error=0x0) at ../lib/packagekit-glib2/pk-client.c:245
#9  0x00007f74dff0ce96 in pk_client_signal_finished (state=0x5646812c1720 [PkClientState], exit_enum=PK_EXIT_ENUM_SUCCESS, runtime=7264)
    at ../lib/packagekit-glib2/pk-client.c:1202
#10 0x00007f74dff0d279 in pk_client_signal_cb
    (proxy=0x5646812c1390 [GDBusProxy], sender_name=0x7f74c0009610 ":1.360", signal_name=0x7f74c0008e40 "Finished", parameters=0x7f74c0003b60, user_data=0x5646812b9560) at ../lib/packagekit-glib2/pk-client.c:1284
#15 0x00007f74dfd7a2a0 in <emit signal 'g-signal' on instance 0x5646812c1390 [GDBusProxy]>
    (instance=instance@entry=0x5646812c1390, signal_id=<optimized out>, detail=<optimized out>) at ../gobject/gsignal.c:3583
    #11 0x00007f74dfd5e5fa in g_closure_invoke
    (closure=0x5646812aa800, return_value=0x0, n_param_values=4, param_values=0x7ffe60ccb6c0, invocation_hint=0x7ffe60ccb610)
    at ../gobject/gclosure.c:834
    #12 0x00007f74dfd72b16 in signal_emit_unlocked_R
    (node=node@entry=0x7ffe60ccb7c0, detail=detail@entry=0, instance=instance@entry=0x5646812c1390, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7ffe60ccb6c0) at ../gobject/gsignal.c:3888
    #13 0x00007f74dfd744c2 in signal_emit_valist_unlocked
    (instance=instance@entry=0x5646812c1390, signal_id=signal_id@entry=12, detail=detail@entry=0, var_args=var_args@entry=0x7ffe60ccb930)
    at ../gobject/gsignal.c:3520
    #14 0x00007f74dfd7a1de in g_signal_emit_valist (instance=0x5646812c1390, signal_id=12, detail=0, var_args=0x7ffe60ccb930)
    at ../gobject/gsignal.c:3263
#16 0x00007f74dfc8b205 in on_signal_received
    (connection=<optimized out>, sender_name=0x7f74c0006fb0 ":1.360", object_path=<optimized out>, interface_name=<optimized out>, signal_name=0x7f74c00094f0 "Finished", parameters=0x7f74c0003b60, user_data=0x5646812b0180) at ../gio/gdbusproxy.c:874
#17 0x00007f74dfc77395 in emit_signal_instance_in_idle_cb (data=0x7f74c0009240) at ../gio/gdbusconnection.c:3798
#18 0x00007f74dfe02377 in g_main_dispatch (context=context@entry=0x5646812a1dd0) at ../glib/gmain.c:3344
#19 0x00007f74dfe05677 in g_main_context_dispatch_unlocked (context=0x5646812a1dd0) at ../glib/gmain.c:4152
#20 g_main_context_iterate_unlocked (context=0x5646812a1dd0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>)
    at ../glib/gmain.c:4217
#21 0x00007f74dfe05fd7 in g_main_loop_run (loop=0x5646812a1ff0) at ../glib/gmain.c:4419
#22 0x0000564680126113 in main (argc=3, argv=0x7ffe60ccc008) at ../client/pk-console.c:2400
joebonrichie commented 2 months ago

TODO: test commits from this branch https://github.com/PackageKit/PackageKit/pull/756#issuecomment-2167905415 as well as #756

joebonrichie commented 1 month ago

Resolved by https://github.com/PackageKit/PackageKit/pull/801