From ced154500de1dde42033579a7b29494934d8a02d Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 7 Dec 2012 15:29:06 +0100 Subject: a11y: Do not refer to destructed QObject in Windows bridge The crash could happen if a QWidget in the UI got deleted, and the AT client later tried to access the widget through the cache (qAccessibleRecentSentEvents()). Solution: Use a QPointer as a guard. Task-number: QTBUG-26187 Change-Id: I1aa716766626cf171757e76ba255a6d5ae4fd854 Reviewed-by: Frederik Gladhorn --- .../windows/accessible/qwindowsaccessibility.cpp | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp') diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index db2d5f949f..b94fef56ba 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -87,10 +88,9 @@ // This stuff is used for widgets/items with no window handle: -typedef QMap > NotifyMap; +typedef QMap,int> > NotifyMap; Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents) - QT_BEGIN_NAMESPACE @@ -193,14 +193,25 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window); static int eventNum = 0; - if (event->type() != QAccessible::MenuCommand) { // MenuCommand is faked - // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE" + if (event->type() != QAccessible::MenuCommand && // MenuCommand is faked + event->type() != QAccessible::ObjectDestroyed) { + /* In some rare occasions, the server (Qt) might get a ::get_accChild call with a + childId that references an entry in the cache where there was a dangling + QObject-pointer. Previously we crashed on this. + + There is no point in actually notifying the AT client that the object got destroyed, + because the AT client won't query for get_accChild if the event is ObjectDestroyed + anyway, and we have no other way of mapping the eventId argument to the actual + child/descendant object. (Firefox seems to simply completely ignore + EVENT_OBJECT_DESTROY). + + We therefore guard each QObject in the cache with a QPointer, and only notify the AT + client if the type is not ObjectDestroyed. + */ eventNum %= 50; //[0..49] int eventId = - (eventNum - 1); - - qAccessibleRecentSentEvents()->insert(eventId, qMakePair(event->object(), event->child())); - ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId ); - + qAccessibleRecentSentEvents()->insert(eventId, qMakePair(QPointer(event->object()), event->child())); + ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId); ++eventNum; } #endif // Q_OS_WINCE @@ -244,7 +255,8 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc) */ QPair QWindowsAccessibility::getCachedObject(int entryId) { - return qAccessibleRecentSentEvents()->value(entryId); + QPair, int> pair = qAccessibleRecentSentEvents()->value(entryId); + return qMakePair(pair.first.data(), pair.second); } /* -- cgit v1.2.3