https://bugs.kde.org/show_bug.cgi?id=517865

            Bug ID: 517865
           Summary: KisBusyWaitBroker crashes on null qApp->thread()
                    during Qt global static destruction on exit
    Classification: Applications
           Product: krita
      Version First 5.2.2
       Reported In:
          Platform: Ubuntu
                OS: Linux
            Status: REPORTED
          Severity: crash
          Priority: NOR
         Component: General
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

## Summary

Krita crashes with SIGSEGV on exit. The crash occurs in KisBusyWaitBroker.cpp
at the qApp->thread() call inside notifyWaitOnImageStarted(), because qApp is
already null at that point.

## Root Cause

KisPart and QApplication are both Q_GLOBAL_STATIC objects. C++ does not
guarantee destruction order across translation units. When QApplication
destructs before KisPart, the following chain triggers:

  KisPart Q_GLOBAL_STATIC Holder::~Holder()         (KisPart.cpp:85)
  → KisPart::~KisPart() → delete d                  (KisPart.cpp:189)
  → KisAnimationCachePopulator::~KisAnimationCachePopulator()
      clears priorityFrames QVector                 
(kis_animation_cache_populator.cpp:301)
  → KisSharedPtr<KisImage> refcount drops to 0
  → KisImage::~KisImage() → waitForDone()            (kis_image.cc:316)
  → KisBusyWaitBroker::notifyWaitOnImageStarted()
  → qApp->thread()  ← SIGSEGV: qApp is null         (KisBusyWaitBroker.cpp:47)

The same vulnerable pattern appears 4 times in KisBusyWaitBroker.cpp:
- notifyWaitOnImageStarted()   line 47
- notifyWaitOnImageEnded()
- notifyGeneralWaitStarted()
- notifyGeneralWaitEnded()

## Proposed Fix

In all four functions in libs/image/KisBusyWaitBroker.cpp, change:

  if (QThread::currentThread() != qApp->thread()) return;

to:

  if (!qApp || QThread::currentThread() != qApp->thread()) return;

## Stack Trace (with debug symbols)

#0  QObject::thread() const () at libQt5Core.so.5
#1  KisBusyWaitBroker::notifyWaitOnImageStarted (this=...) at
KisBusyWaitBroker.cpp:47
       if (QThread::currentThread() != qApp->thread()) return;
#2  KisImage::waitForDone (this=0x5996e9a34400) at kis_image.cc:1839
       KisBusyWaitBroker::instance()->notifyWaitOnImageStarted(this);
#3  KisImage::~KisImage (this=0x5996e9a34400) at kis_image.cc:316
       waitForDone();
#4  KisImage::~KisImage () at kis_image.cc:320
#5  KisSharedPtr<KisImage>::deref () at kis_shared_ptr.h:194
#6  KisSharedPtr<KisImage>::~KisSharedPtr () at kis_shared_ptr.h:100
#7  QPair<KisSharedPtr<KisImage>, int>::~QPair ()
#8  QVector<QPair<KisSharedPtr<KisImage>, int>>::clear ()
#9  KisAnimationCachePopulator::~KisAnimationCachePopulator () at
kis_animation_cache_populator.cpp:301
       m_d->priorityFrames.clear();
#10 KisPart::Private::~Private () at KisPart.cpp:101
#11 KisPart::~KisPart () at KisPart.cpp:189
       delete d;
#12 Q_GLOBAL_STATIC KisPart Holder::~Holder() at KisPart.cpp:85
#13 __run_exit_handlers (status=0) at exit.c:108
#14 __GI_exit (status=0)

## Environment

- OS: Ubuntu 24.04 (Noble)
- Krita version: 5.2.2 (package krita 1:5.2.2+dfsg-2build8)
- Qt5Core version: 5.15.x
- Signal: SIGSEGV (11)
- Triggered by: opening a JPEG file then exiting normally

## Verification

The bug has been confirmed present and unpatched on:
- libs/image/KisBusyWaitBroker.cpp on branch master
- libs/image/KisBusyWaitBroker.cpp on branch krita/5.2
- libs/image/KisBusyWaitBroker.cpp on release/5.2.15

The file has had only 4 commits since its introduction in 2020. No existing bug
report covers this specific scenario.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to