[frameworks/kcoreaddons] /: Don't let fromAppStreamFile() modify the application data

David Faure <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 0a767016dbb83cc8423037a084ab9fc0c45eb0da by David Faure.
Committed on 25/07/2026 at 17:53.
Pushed by dfaure into branch 'master'.

Don't let fromAppStreamFile() modify the application data

It looks like a factory, but it filled in s_registry->m_appData, so
reading AppStream data changed the application identity: a <provides>
entry overwrites the component name, and the next setApplicationData()
call (KMainWindow does one per window) pushes that into
QCoreApplication::applicationName().

In KMail this renamed the application from "kmail2" to "kmail" while it
was running, so every window created afterwards looked for its .rc file
under the wrong component and came up with just the ui_standards.rc
menus.

Fill in a copy instead; callers that want the result to become the
application data still call setApplicationData() themselves.

M  +14   -0    autotests/kaboutdatatest.cpp
M  +6    -6    src/lib/kaboutdata.cpp

https://invent.kde.org/frameworks/kcoreaddons/-/commit/0a767016dbb83cc8423037a084ab9fc0c45eb0da

diff --git a/autotests/kaboutdatatest.cpp b/autotests/kaboutdatatest.cpp
index 285f47ec..3f545244 100644
--- a/autotests/kaboutdatatest.cpp
+++ b/autotests/kaboutdatatest.cpp
@@ -47,6 +47,7 @@ private Q_SLOTS:
     void testProductName();
     void testAppStream();
     void testAppStreamLocalized();
+    void testAppStreamKeepsApplicationData();
 };
 
 static const char AppName[] = "app";
@@ -471,6 +472,19 @@ void KAboutDataTest::testAppStreamLocalized()
         "<p>&quot;Cool&quot; (untranslated) Features:</p><ul><li><em>Important</em> untranslated feature release change 1.</li><li>Not so <em>important</em> untranslated feature release change 2.</li><li>Feature release change 3.</li></ul>"_L1);
 }
 
+// Reading AppStream data must not modify the application data, in particular not its
+// component name, which QCoreApplication::applicationName() is kept in sync with.
+void KAboutDataTest::testAppStreamKeepsApplicationData()
+{
+    KAboutData::setApplicationData(KAboutData(u"myapp"_s, u"My App"_s));
+    QCOMPARE(QCoreApplication::applicationName(), "myapp"_L1);
+
+    std::ignore = KAboutData::fromAppStreamFile(QFINDTESTDATA("data/org.kde.coreaddons.test-app.xml"_L1));
+
+    QCOMPARE(KAboutData::applicationData().componentName(), "myapp"_L1);
+    QCOMPARE(QCoreApplication::applicationName(), "myapp"_L1);
+}
+
 QTEST_MAIN(KAboutDataTest)
 
 #include "kaboutdatatest.moc"
diff --git a/src/lib/kaboutdata.cpp b/src/lib/kaboutdata.cpp
index 52eef2db..c37648c9 100644
--- a/src/lib/kaboutdata.cpp
+++ b/src/lib/kaboutdata.cpp
@@ -1533,12 +1533,12 @@ struct {
 
 KAboutData KAboutData::fromAppStreamFile(const QString &appStreamFileName)
 {
-    KAboutData *aboutData = s_registry->m_appData;
-    if (!aboutData) {
-        aboutData = new KAboutData(QCoreApplication::applicationName(), QString(), QString());
-        aboutData->setBugAddress(QByteArray());
-        s_registry->m_appData = aboutData;
-    }
+    // Start from the application data, but fill in a copy: writing to the application data here
+    // would change the application identity behind the caller's back. In particular a <provides>
+    // entry overwrites the component name, which the next setApplicationData() call then pushes
+    // into QCoreApplication::applicationName().
+    KAboutData result = KAboutData::applicationData();
+    KAboutData *aboutData = &result;
 
     QFile appStreamFile(appStreamFileName);
     if (appStreamFile.fileName().isEmpty() || !appStreamFile.open(QFile::ReadOnly)) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.