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 <frederik.gladhorn@digia.com>
This commit is contained in:
parent
03e1e4138c
commit
ced154500d
@ -48,6 +48,7 @@
|
||||
#include <QtCore/qlocale.h>
|
||||
#include <QtCore/qmap.h>
|
||||
#include <QtCore/qpair.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtGui/qaccessible.h>
|
||||
#include <QtGui/qaccessible2.h>
|
||||
@ -87,10 +88,9 @@
|
||||
|
||||
|
||||
// This stuff is used for widgets/items with no window handle:
|
||||
typedef QMap<int, QPair<QObject*,int> > NotifyMap;
|
||||
typedef QMap<int, QPair<QPointer<QObject>,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<QObject>(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<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId)
|
||||
{
|
||||
return qAccessibleRecentSentEvents()->value(entryId);
|
||||
QPair<QPointer<QObject>, int> pair = qAccessibleRecentSentEvents()->value(entryId);
|
||||
return qMakePair(pair.first.data(), pair.second);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -757,7 +757,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI
|
||||
acc = res;
|
||||
}
|
||||
} else {
|
||||
qWarning("get_accChild got a negative varChildID, but did not find it in cache");
|
||||
qWarning("get_accChild got a negative varChildID (%d), but did not find it in cache", childIndex);
|
||||
}
|
||||
} else {
|
||||
if (childIndex) {
|
||||
|
Loading…
Reference in New Issue
Block a user