Fix KProcessRunner systemd code path for Qt6
Open, Needs TriagePublic

Description

As can be seen in https://invent.kde.org/frameworks/kio/-/merge_requests/677#note_361955, the systemd code path in KProcessRunner causes an exception to be thrown; this causes openurljob, commandlauncherjob, dropjob, applicationlauncherjob unittests to fail (the service and scope variants for the ones in KIOGui, the forking variant passes):

To reproduce the issue, build KIO with Qt6 (MR link above), then:

export KDE_APPLICATIONS_AS_SERVICE=1; export KDE_APPLICATIONS_AS_SCOPE=0;
gdb build/bin/commandlauncherjob_servicetest
catch throw

I got this backtrace:

#0  0x00007ffff5fa9472 in __cxa_throw () from /lib64/libstdc++.so.6
#1  0x00007ffff61d3a21 in qBadAlloc () at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/global/qglobal.cpp:3270
#2  0x00007ffff61e423d in QByteArray::QByteArray (this=<optimized out>, size=<optimized out>, this=<optimized out>, size=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/text/qbytearray.cpp:1718
#3  0x00007ffff634feb9 in QUtf8::convertFromUnicode (in=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/text/qstringconverter.cpp:492
#4  0x00007ffff633f7ee in qt_convert_to_utf8 (str=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/text/qstring.cpp:5257
#5  QString::toUtf8_helper (str=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/text/qstring.cpp:5249
#6  0x00007ffff6720992 in QString::toUtf8() const & (this=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/build/include/QtCore/../../../src/corelib/text/qstring.h:745
#7  QDBusMarshaller::append (this=0x7fffffffc020, arg=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmarshaller.cpp:136
#8  0x00007ffff671ae1f in QDBusMarshaller::append (arg=..., this=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmarshaller.cpp:246
#9  QDBusArgument::operator<< (this=0x7fffffffc1a0, arg=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusargument.cpp:530
#10 0x00007ffff7f917fb in operator<< (execCommand=..., argument=...) at /home/ahmad/dev6/kio/src/gui/systemd/dbustypes.h:49
#11 operator<< <QList, <unnamed struct> > (list=..., arg=...) at /usr/include/qt6/QtDBus/qdbusargument.h:237
#12 operator() (t=<optimized out>, arg=..., __closure=0x0) at /usr/include/qt6/QtDBus/qdbusmetatype.h:69
#13 _FUN () at /usr/include/qt6/QtDBus/qdbusmetatype.h:69
#14 0x00007ffff6757378 in QDBusMetaType::marshall (arg=..., metaType=..., data=0x5555555b6ef0)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmetatype.cpp:255
#15 0x00007ffff678286d in QDBusMarshaller::appendRegisteredType (arg=..., this=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmarshaller.cpp:520
#16 QDBusMarshaller::appendVariantInternal(QVariant const&) [clone .isra.0] (this=<optimized out>, arg=...)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmarshaller.cpp:493
#17 0x00007ffff6782d6f in QDBusMessagePrivate::toDBusMessage(QDBusMessage const&, QFlags<QDBusConnection::ConnectionCapability>, QDBusError*) [clone .isra.0]
    (capabilities=..., error=error@entry=0x7fffffffc610, message=..., message=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusmessage.cpp:197
#18 0x00007ffff673b77e in QDBusConnectionPrivate::sendWithReplyAsync (this=<optimized out>, message=..., receiver=<optimized out>, 
    returnMethod=<optimized out>, errorMethod=<optimized out>, timeout=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/build/include/QtCore/../../../src/corelib/global/qflags.h:69
#19 0x00007ffff6728f26 in QDBusConnection::asyncCall (this=<optimized out>, message=..., timeout=<optimized out>)
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusconnection.cpp:691
#20 0x00007ffff671cb9c in QDBusAbstractInterface::asyncCallWithArgumentList (this=this@entry=0x5555555b49a0, method=..., args=...)
--Type <RET> for more, q to quit, c to continue without paging--c
    at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/dbus/qdbusabstractinterface.cpp:527
#21 0x00007ffff7f9c769 in OrgFreedesktopSystemd1ManagerInterface::StartTransientUnit (aux=..., properties=..., mode=..., name=..., this=0x5555555b49a0) at /home/ahmad/dev6/kio/build/src/gui/managerinterface.h:44
#22 SystemdProcessRunner::startProcess (this=0x5555555abae0) at /home/ahmad/dev6/kio/src/gui/systemd/systemdprocessrunner.cpp:117
#23 0x00007ffff7f7e3b1 in KProcessRunner::initFromDesktopName (this=0x5555555abae0, desktopName=..., execName=..., iconName=..., asn=..., workingDirectory=..., environment=...) at /home/ahmad/dev6/kio/src/gui/kprocessrunner.cpp:203
#24 0x00007ffff7f7e5f0 in KProcessRunner::fromCommand (cmd=..., desktopName=..., execName=..., iconName=..., asn=..., workingDirectory=..., environment=...) at /home/ahmad/dev6/kio/src/gui/kprocessrunner.cpp:162
#25 0x00007ffff7f72920 in KIO::CommandLauncherJob::start (this=0x5555555af360) at /home/ahmad/dev6/kio/src/gui/commandlauncherjob.cpp:127
#26 0x00007ffff79b79a0 in KJob::exec (this=this@entry=0x5555555af360) at /home/ahmad/dev6/kcoreaddons/src/lib/jobs/kjob.cpp:193
#27 0x0000555555558b98 in CommandLauncherJobTest::startProcessAsCommand (this=0x7fffffffdc60) at /home/ahmad/dev6/kio/autotests/commandlauncherjobtest.cpp:63
#28 0x00007ffff6289bb6 in QMetaMethod::invoke (this=<optimized out>, object=0x7fffffffdc60, connectionType=connectionType@entry=Qt::DirectConnection, returnValue=..., val0=..., val1=..., val2=..., val3=..., val4=..., val5=..., val6=..., val7=..., val8=..., val9=...) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/corelib/kernel/qmetaobject.cpp:2390
#29 0x00007ffff7ef948a in QMetaMethod::invoke (val9=..., val8=..., val7=..., val6=..., val5=..., val4=..., val3=..., val2=..., val1=..., val0=..., connectionType=Qt::DirectConnection, object=<optimized out>, this=<optimized out>) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/build/include/QtCore/../../../src/corelib/kernel/qobjectdefs.h:116
#30 QTest::TestMethods::invokeTestOnData (index=<optimized out>, this=0x7fffffffd8a0) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/testlib/qtestcase.cpp:950
#31 QTest::TestMethods::invokeTest (watchDog=<optimized out>, data=<optimized out>, index=<optimized out>, this=0x7fffffffd8a0) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/testlib/qtestcase.cpp:1182
#32 QTest::TestMethods::invokeTests (testObject=<optimized out>, this=0x7fffffffd8a0) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/testlib/qtestcase.cpp:1525
#33 QTest::qRun () at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/testlib/qtestcase.cpp:1952
#34 0x00007ffff7eef3ec in QTest::qExec (testObject=testObject@entry=0x7fffffffdc60, argc=<optimized out>, argv=argv@entry=0x7fffffffddc8) at /usr/src/debug/qt6-base-6.2.2-19.2.x86_64/src/testlib/qtestcase.cpp:1860
#35 0x0000555555557837 in main (argc=<optimized out>, argv=0x7fffffffddc8) at /home/ahmad/dev6/kio/autotests/commandlauncherjobtest.cpp:18

Can someone else verify this. I ran the test and did not get any thrown issues in the method mentioned.
I did get an issue with the test not completing, but it was well after the DBus message was sent and we'd gone through this code.

My qtbase is latest dev as of 05/01/2022

Interesting. I have Qt 6.2.2 (what's in Tumbleweed repos), I don't build Qt from source.

vkrause added a subscriber: vkrause.Jan 6 2022, 4:04 PM

I can reproduce what Ahmad sees here (self-compiled Qt 6.3).

With the following changes it passes the D-Bus part and gets stuck, ie. I can also reproduce what David sees.

diff --git a/src/gui/systemd/dbustypes.h b/src/gui/systemd/dbustypes.h
index 81bc1a070..4cabc620e 100644
--- a/src/gui/systemd/dbustypes.h
+++ b/src/gui/systemd/dbustypes.h
@@ -34,7 +34,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, QVariantMu
     return argument;
 }

-using ExecCommand = struct {
+struct ExecCommand {
     QString path;
     QStringList argv;
     bool ignoreFailure;
@@ -59,7 +59,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, ExecComman
     return argument;
 }

-using TransientAux = struct {
+struct TransientAux {
     QString name;
     QVariantMultiMap properties;
 };

(I knew declaration-and-definition-rolled-into-one are not nice, but didn't know they could be this bad :-)).

I'm not saying this is the right fix for the problem at hand, I don't fully understand that yet myself. This is just meant as documenting my local observations :)

meven added a subscriber: meven.Feb 2 2023, 10:56 AM

I can reproduce what Ahmad sees here (self-compiled Qt 6.3).

With the following changes it passes the D-Bus part and gets stuck, ie. I can also reproduce what David sees.

diff --git a/src/gui/systemd/dbustypes.h b/src/gui/systemd/dbustypes.h
index 81bc1a070..4cabc620e 100644
--- a/src/gui/systemd/dbustypes.h
+++ b/src/gui/systemd/dbustypes.h
@@ -34,7 +34,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, QVariantMu
     return argument;
 }

-using ExecCommand = struct {
+struct ExecCommand {
     QString path;
     QStringList argv;
     bool ignoreFailure;
@@ -59,7 +59,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, ExecComman
     return argument;
 }

-using TransientAux = struct {
+struct TransientAux {
     QString name;
     QVariantMultiMap properties;
 };

Fix has been shipped https://invent.kde.org/frameworks/kio/-/commit/a3462e6d4d695ef2e1bb918cb1057ad633be0ecd

vkrause moved this task from Backlog to Done on the KF6 board.Feb 19 2023, 3:51 PM