Cocoa integration: do not use released session

QTBUG_10735_crashWithDialog started to show flakyness recently - it crashes,
but not every time (which fits the definition of UB perfectly).

While the test itself is doing weird things and puts our event dispatcher
into a weird state, our API allows to:

1. Using QDialog to enter event loop (with runModalSession under the hood), then ...
2. to call from a slot (e.g. timer-attached) QApplication::closeAllWindows() while ...
3. we are still inside that special loop and using the 'session' object, thus ...
4. on the next iteration with [NSApp runModalSession:session] we'll re-use already released
   session (released by endModalSession which in turn was called indirectly by closeAllWindows).

And Cocoa gives us a warning/hint: "Use of freed session detected. Do not call
runModalSession: after calling endModalSesion:."

Task-number: QTBUG-62589
Change-Id: Ie651cee1fba43cfd2b0fc44af5eddc5fd52e2907
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
bb10
Timur Pocheptsov 2017-08-25 16:06:44 +02:00
parent de6d6eb13e
commit 0270651dda
1 changed files with 11 additions and 1 deletions

View File

@ -401,8 +401,18 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// [NSApp run], which is the normal code path for cocoa applications.
if (NSModalSession session = d->currentModalSession()) {
QBoolBlocker execGuard(d->currentExecIsNSAppRun, false);
while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt)
while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt) {
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
if (session != d->currentModalSessionCached) {
// It's possible to release the current modal session
// while we are in this loop, for example, by closing all
// windows from a slot via QApplication::closeAllWindows.
// In this case we cannot use 'session' anymore. A warning
// from Cocoa is: "Use of freed session detected. Do not
// call runModalSession: after calling endModalSesion:."
break;
}
}
if (!d->interrupt && session == d->currentModalSessionCached) {
// Someone called [NSApp stopModal:] from outside the event