Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kf6-kservice for openSUSE:Factory 
checked in at 2026-03-04 21:02:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kf6-kservice (Old)
 and      /work/SRC/openSUSE:Factory/.kf6-kservice.new.561 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kf6-kservice"

Wed Mar  4 21:02:53 2026 rev:25 rq:1335919 version:6.23.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/kf6-kservice/kf6-kservice.changes        
2026-02-16 13:06:37.019301171 +0100
+++ /work/SRC/openSUSE:Factory/.kf6-kservice.new.561/kf6-kservice.changes       
2026-03-04 21:03:27.432068429 +0100
@@ -1,0 +2,8 @@
+Mon Mar  2 21:21:54 UTC 2026 - Christophe Marin <[email protected]>
+
+- Update to 6.23.1:
+  * ksycocafactory: guard against integer underflow
+  * ksycocafactory: do not crash when failing to find a factory stream
+  * ksycoca: do not allow for recursive repairs (kde#516426)
+
+-------------------------------------------------------------------

Old:
----
  kservice-6.23.0.tar.xz
  kservice-6.23.0.tar.xz.sig

New:
----
  kservice-6.23.1.tar.xz
  kservice-6.23.1.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kf6-kservice.spec ++++++
--- /var/tmp/diff_new_pack.K2T9lX/_old  2026-03-04 21:03:31.768247659 +0100
+++ /var/tmp/diff_new_pack.K2T9lX/_new  2026-03-04 21:03:31.784248321 +0100
@@ -20,10 +20,11 @@
 
 %define rname kservice
 # Full KF6 version (e.g. 6.23.0)
-%{!?_kf6_version: %global _kf6_version %{version}}
+# %%{!?_kf6_version: %%global _kf6_version %%{version}}
+%global _kf6_version 6.23.0
 %bcond_without released
 Name:           kf6-kservice
-Version:        6.23.0
+Version:        6.23.1
 Release:        0
 Summary:        Plugin framework for desktop services
 License:        LGPL-2.1-or-later


++++++ kservice-6.23.0.tar.xz -> kservice-6.23.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/CMakeLists.txt 
new/kservice-6.23.1/CMakeLists.txt
--- old/kservice-6.23.0/CMakeLists.txt  2026-02-06 13:16:56.000000000 +0100
+++ new/kservice-6.23.1/CMakeLists.txt  2026-03-02 16:30:35.000000000 +0100
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.27)
 
-set(KF_VERSION "6.23.0") # handled by release scripts
+set(KF_VERSION "6.23.1") # handled by release scripts
 set(KF_DEP_VERSION "6.23.0") # handled by release scripts
 project(KService VERSION ${KF_VERSION})
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/autotests/kservicetest.cpp 
new/kservice-6.23.1/autotests/kservicetest.cpp
--- old/kservice-6.23.0/autotests/kservicetest.cpp      2026-02-06 
13:16:56.000000000 +0100
+++ new/kservice-6.23.1/autotests/kservicetest.cpp      2026-03-02 
16:30:35.000000000 +0100
@@ -1,6 +1,6 @@
 /*
     SPDX-FileCopyrightText: 2006 David Faure <[email protected]>
-    SPDX-FileCopyrightText: 2022 Harald Sitter <[email protected]>
+    SPDX-FileCopyrightText: 2022-2026 Harald Sitter <[email protected]>
 
     SPDX-License-Identifier: LGPL-2.0-only
 */
@@ -25,6 +25,7 @@
 #include <kservicegroup.h>
 
 #include <QFile>
+#include <QScopedValueRollback>
 #include <QSignalSpy>
 #include <QStandardPaths>
 #include <QThread>
@@ -33,6 +34,9 @@
 #include <QLoggingCategory>
 #include <QMimeDatabase>
 
+using namespace std::chrono_literals;
+using namespace Qt::StringLiterals;
+
 QTEST_MAIN(KServiceTest)
 
 extern KSERVICE_EXPORT int ksycoca_ms_between_checks;
@@ -572,4 +576,31 @@
     }
 }
 
+void KServiceTest::testRecursiveUpdate()
+{
+    if (!KSycoca::isAvailable()) {
+        QSKIP("ksycoca not available");
+    }
+
+    // Make sure updates trigger immediately.
+    QScopedValueRollback rollback(ksycoca_ms_between_checks, 0);
+
+    const QString filePath = 
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + 
"/org.kde.testRecursiveUpdate.desktop"_L1;
+    {
+        QFile f(filePath);
+        QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
+    }
+    QVERIFY(QFile::exists(filePath));
+
+    QSignalSpy spy(KSycoca::self(), &KSycoca::databaseChanged);
+
+    auto service = KService::serviceByDesktopPath(filePath);
+    // The signal must not have fired already. If it had we'd be able to 
recursively update and break the singleton.
+    QCOMPARE(spy.count(), 0);
+
+    // If we event loop it should fire though.
+    spy.wait(4s);
+    QCOMPARE(spy.count(), 1);
+}
+
 #include "moc_kservicetest.cpp"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/autotests/kservicetest.h 
new/kservice-6.23.1/autotests/kservicetest.h
--- old/kservice-6.23.0/autotests/kservicetest.h        2026-02-06 
13:16:56.000000000 +0100
+++ new/kservice-6.23.1/autotests/kservicetest.h        2026-03-02 
16:30:35.000000000 +0100
@@ -1,6 +1,6 @@
 /*
     SPDX-FileCopyrightText: 2006 David Faure <[email protected]>
-    SPDX-FileCopyrightText: 2022 Harald Sitter <[email protected]>
+    SPDX-FileCopyrightText: 2022-2026 Harald Sitter <[email protected]>
 
     SPDX-License-Identifier: LGPL-2.0-only
 */
@@ -46,6 +46,7 @@
     void testAliasFor();
     void testServiceActionService();
     void testStartupNotify();
+    void testRecursiveUpdate();
 
 private:
     void runKBuildSycoca(bool noincremental = false);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/src/services/kservicefactory.cpp 
new/kservice-6.23.1/src/services/kservicefactory.cpp
--- old/kservice-6.23.0/src/services/kservicefactory.cpp        2026-02-06 
13:16:56.000000000 +0100
+++ new/kservice-6.23.1/src/services/kservicefactory.cpp        2026-03-02 
16:30:35.000000000 +0100
@@ -13,6 +13,7 @@
 #include "servicesdebug.h"
 #include <QDir>
 #include <QFile>
+#include <QScopedValueRollback>
 
 extern int servicesDebugArea();
 
@@ -22,6 +23,18 @@
     , m_relNameDict(nullptr)
     , m_menuIdDict(nullptr)
 {
+    // Safety net against recursive calls. Because KSycocaFactory calls 
findFactory and that issues a checkDatabase
+    // and that may end up repairing the database and thus closing and 
reopening it, we must absolutely never find
+    // ourselves in a recursive call chain.
+    // The inner call would thrash the state of the outer call causing 
impossibly difficult to debug state corruption.
+    thread_local bool inside = false;
+    if (inside) {
+        qFatal(
+            "Recursive call detected in KServiceFactory. This is not allowed 
and indicates a bug in KSycoca/KServiceFactory. Please report this on "
+            "bugs.kde.org.");
+    }
+    QScopedValueRollback guard(inside, true);
+
     m_offerListOffset = 0;
     m_nameDictOffset = 0;
     m_relNameDictOffset = 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/src/sycoca/ksycoca.cpp 
new/kservice-6.23.1/src/sycoca/ksycoca.cpp
--- old/kservice-6.23.0/src/sycoca/ksycoca.cpp  2026-02-06 13:16:56.000000000 
+0100
+++ new/kservice-6.23.1/src/sycoca/ksycoca.cpp  2026-03-02 16:30:35.000000000 
+0100
@@ -320,7 +320,12 @@
         m_databasePath = findDatabase();
 
         // Now notify applications
-        Q_EMIT q->databaseChanged();
+        QMetaObject::invokeMethod(q,
+                                  &KSycoca::databaseChanged,
+                                  // Guard against recursive call chains 
caused by database updates.
+                                  // Because of the self-healing nature of 
KSycoca we must absolutely never find ourselves in a recursive call chain
+                                  // where one database change causes another 
database change (for example because there was an intermediate file change).
+                                  Qt::QueuedConnection);
     }
 }
 
@@ -676,7 +681,12 @@
         qCDebug(SYCOCA) << "Still no database...";
         return false;
     }
-    Q_EMIT q->databaseChanged();
+    QMetaObject::invokeMethod(q,
+                              &KSycoca::databaseChanged,
+                              // Guard against recursive call chains caused by 
database updates.
+                              // Because of the self-healing nature of KSycoca 
we must absolutely never find ourselves in a recursive call chain
+                              // where one database change causes another 
database change (for example because there was an intermediate file change).
+                              Qt::QueuedConnection);
     return true;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kservice-6.23.0/src/sycoca/ksycocafactory.cpp 
new/kservice-6.23.1/src/sycoca/ksycocafactory.cpp
--- old/kservice-6.23.0/src/sycoca/ksycocafactory.cpp   2026-02-06 
13:16:56.000000000 +0100
+++ new/kservice-6.23.1/src/sycoca/ksycocafactory.cpp   2026-03-02 
16:30:35.000000000 +0100
@@ -34,27 +34,42 @@
     int m_beginEntryOffset = 0;
     int m_endEntryOffset = 0;
     KSycocaDict *m_sycocaDict = nullptr;
+    // Used to avoid crashes when the factory failed to locate an actual data 
stream.
+    // Mind that we need a backing buffer since callers also tap into the 
stream's QIODevice.
+    QByteArray m_fallbackBuffer;
+    QDataStream m_fallbackStream{m_fallbackBuffer};
 };
 
 KSycocaFactory::KSycocaFactory(KSycocaFactoryId factory_id, KSycoca *sycoca)
     : m_sycoca(sycoca)
     , d(new KSycocaFactoryPrivate)
 {
-    if (!m_sycoca->isBuilding() && (m_str = 
m_sycoca->findFactory(factory_id))) {
-        // Read position of index tables....
-        qint32 i;
-        (*m_str) >> i;
-        d->m_sycocaDictOffset = i;
-        (*m_str) >> i;
-        d->m_beginEntryOffset = i;
-        (*m_str) >> i;
-        d->m_endEntryOffset = i;
-
-        QDataStream *str = stream();
-        qint64 saveOffset = str->device()->pos();
-        // Init index tables
-        d->m_sycocaDict = new KSycocaDict(str, d->m_sycocaDictOffset);
-        saveOffset = str->device()->seek(saveOffset);
+    if (!m_sycoca->isBuilding()) {
+        m_str = m_sycoca->findFactory(factory_id);
+        if (m_str) {
+            // Read position of index tables....
+            qint32 i;
+            (*m_str) >> i;
+            d->m_sycocaDictOffset = i;
+            (*m_str) >> i;
+            d->m_beginEntryOffset = i;
+            (*m_str) >> i;
+            d->m_endEntryOffset = i;
+
+            QDataStream *str = stream();
+            qint64 saveOffset = str->device()->pos();
+            // Init index tables
+            d->m_sycocaDict = new KSycocaDict(str, d->m_sycocaDictOffset);
+            saveOffset = str->device()->seek(saveOffset);
+        } else {
+            qWarning() << "Could not find factory with id" << int(factory_id)
+                       << "in sycoca database, you must run kbuildsycoca 
first! Creating a fake stream to not crash.";
+            m_str = &d->m_fallbackStream;
+            m_entryDict = new KSycocaEntryDict;
+            d->m_sycocaDict = new KSycocaDict;
+            d->m_beginEntryOffset = 0;
+            d->m_endEntryOffset = 0;
+        }
     } else {
         // We are in kbuildsycoca -- build new database!
         m_entryDict = new KSycocaEntryDict;
@@ -186,8 +201,8 @@
     qint32 entryCount;
     (*str) >> entryCount;
 
-    if (entryCount > 8192) {
-        qCWarning(SYCOCA) << QThread::currentThread() << "error detected in 
factory" << this;
+    if (entryCount < 0 || entryCount > 8192) { // mind that new accepts a 
size_t (unsigned) but we are dealing with an int here
+        qCWarning(SYCOCA) << QThread::currentThread() << "error detected in 
factory" << this << entryCount;
         KSycoca::flagError();
         return list;
     }

Reply via email to