Weird crash with QSystemTrayIcon on OSX
I have a Qt 4.8.4 application that I'm maintaining that is seeing a peculiar crash on OSX, and I'm having a difficult time understanding what is going on. The application has two modes - in the in-program mode, it has a QMainWindow that owns a QSystemTrayIcon. The application can quit back to it's pre-program mode where it has a different QMainWindow that doesn't have the QSystemTrayIcon.
When we switch from our in-program QMainWindow back to our pre-program QMainWindow, the QSystemTrayIcon gets deleted (I've derived from it and checked when the destructor gets called), but sometimes after the QSystemTrayIcon object is deleted, the program segfaults. The stack trace we see is:
@Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x919914ab objc_msgSend + 27
1 libQtGui_debug.4.dylib 0x01bc11b8 -[QNSImageView drawRect:] + 56
2 com.apple.AppKit 0x9926b833 -[NSView(NSInternal) _recursive:displayRectIgnoringOpacity:inGraphicsContext:CGContext:topView:shouldChangeFontReferenceColor:] + 1125
3 com.apple.AppKit 0x993a8077 -[NSView(NSInternal) _recursive:displayRectIgnoringOpacity:inContext:topView:] + 110
4 com.apple.AppKit 0x993a7f9e -[NSView _drawRectBasedDisplayRectIgnoringOpacity:inContext:] + 268
5 com.apple.AppKit 0x993a7cbe -[NSView displayRectIgnoringOpacity:inContext:] + 492
6 com.apple.AppKit 0x99427f06 __46-[NSView cacheDisplayInRect:toBitmapImageRep:]_block_invoke + 397
7 com.apple.AppKit 0x99427c8f __36-[NSBitmapImageRep _captureDrawing:]_block_invoke + 553
8 com.apple.AppKit 0x9917c9af -[NSBitmapImageRep _performBlockUsingBacking:] + 43
9 com.apple.AppKit 0x994279dd -[NSBitmapImageRep _captureDrawing:] + 199
10 com.apple.AppKit 0x99427901 -[NSView cacheDisplayInRect:toBitmapImageRep:] + 161
11 com.apple.AppKit 0x9980c032 -[NSStatusItem _updateReplicant:] + 809
12 com.apple.AppKit 0x9941a7dd __33-[NSStatusItem _updateReplicants]_block_invoke + 187
13 com.apple.AppKit 0x9941a6d5 -[NSSystemStatusBar _withAdjustmentDeferred:] + 69
14 com.apple.AppKit 0x9941a67b -[NSStatusItem _updateReplicants] + 170
15 com.apple.AppKit 0x9980d144 -[NSStatusItem _updateReplicantsUnlessMenuIsTracking:] + 301
16 com.apple.Foundation 0x9bb8427c __NSFireDelayedPerform + 422
17 com.apple.CoreFoundation 0x939a5ea6 CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION + 22
18 com.apple.CoreFoundation 0x939a5863 __CFRunLoopDoTimer + 1395
19 com.apple.CoreFoundation 0x93a2006d __CFRunLoopDoTimers + 349
20 com.apple.CoreFoundation 0x9395d353 __CFRunLoopRun + 1779
21 com.apple.CoreFoundation 0x9395c9ea CFRunLoopRunSpecific + 394
22 com.apple.CoreFoundation 0x9395c84b CFRunLoopRunInMode + 123
23 com.apple.HIToolbox 0x97d0cb5d RunCurrentEventLoopInMode + 259
24 com.apple.HIToolbox 0x97d0c777 ReceiveNextEventCommon + 163
25 com.apple.HIToolbox 0x97d0c6bd _BlockUntilNextEventMatchingListInModeWithFilter + 92
26 com.apple.AppKit 0x99102349 _DPSNextEvent + 1602
27 com.apple.AppKit 0x99101870 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 119
28 libQtGui_debug.4.dylib 0x01b43875 QEventDispatcherMac::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 2215
29 libQtCore_debug.4.dylib 0x016abce0 QCoreApplication::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 180
30 com.ourcompany.ourapp 0x00166875 View_Qml::processEvents() + 69 (view_qml.cpp:451)
This is happening well after the QSystemTrayIcon has been deleted. When this crash happens, even though the QSystemTrayIcon has been deleted and I'm seeing the pre-program QMainWindow, the system tray icon in the system menubar is still there - as if the QSystemTrayIcon hasn't been deleted.
There's an outstanding bug (https://bugreports.qt-project.org/browse/QTBUG-13131?page=com.atlassian.jira.plugin.system.issuetabpanels:changehistory-tabpanel) thats been around since the 4.7 days and looks suspiciously similar, but there are still differences. I'm inclined to think that I'm doing something wrong here, but short of some great enlightenment here in the forum, my next step is to try to figure out why QSystemTrayIcon can't seem to get rid of the NSStatusItem that it's wrapping.
Can anyone suggest anything?
What happens if you call QSystemTrayIcon->hide() before you delete it. Also try using QSystemTrayIcon->deleteLater() instead of delete QSystemTrayIcon;.
Sometimes there are things pending for the object and calling deleteLater allows the event loop (where you are crashing) to process the signals and events then delete the item automatically for you. This can prevent crashes in certain circumstances and could be your issue right here.
We've tried multiple variations of this. We've tried
We would have tried
...but QSystemTrayIcon doesn't have a close() method!
In every one of these cases, our QSystemTrayIcon gets nicely deleted (according to the printout we have in our dtor), but we still get the crash.
QSystemTrayIcon seems to be a very odd beast, being renderable but not descended from QWidget. The Windows build of this code works perfectly, and has for some time now. But the OSX version gets this mysterious crash.
Can you try with the latest current version that is 4.8.6 ?
Ok - I'll try it with 4.8.6. Our application is still 32-bit so unfortunately this isn't as simple as dropping in a binary update - I have to put together a special 32-bit build.
Then first try with the pre-built package, it should crash the same unless you are doing a special build
Is there a prebuilt 32-bit OSX build? If so I'd gladly use that. I wasn't aware that such a thing existed.
No, there's no 32Bit build since a long time. Just the 64, but Qt is not really hard to compile on OS X
I'm running into a whole lot of build breaks with 4.8.6 and the latest xcode in 32-bit. I'm making a lot of patches to get 4.8.6 to build, and I've completely given up on phonon.
Are 32-bit OSX builds part of your continuous integration system? It seems like recent versions of clang have broken a whole lot of things in Qt...
What if instead of completely deleting the system tray icon you just hide it in the mode where you don't want to display it?
Does that cause a crash too? Or is it just the cleanup? Then you can create it, show it when you want, hide it when you don't, and it looks/acts like the same thing to the end user.
Also, another option is to use the OSX raw code for tray icons instead of the Qt stuff to work around the bug. If you are stuck on old versions of Qt maybe this is an option for you to just #ifdef some mac specific tray icon code. Not ideal but an easy solution.
I don't know, I don't work for Digia, however you can find information about the CI "here":http://qt-project.org/wiki/CI_Overview
But like I said, test with the 64 bit prebuilt package. Creating a minimal compilable example that reproduce the behavior will help creating a patch.