dix: always copy grabs, don't reference them

Introduced in xorg-server-1.13.99.901-2-g9ad0fdb. Storing the grab pointer
in the listener turns out to be a bad idea. If the grab is not an active
grab or an implicit grab, the pointer stored is the one to the grab attached
on the window. This grab may be removed if the client calls UngrabButton or
similar while the touch is still active, leaving a dangling pointer.

To avoid this, copy the grab wherever we need to reference it later. This
is also what we do for pointer/keyboard grabs, where we copy the grab as
soon as it becomes active.

Reported-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2013-04-17 20:15:35 +10:00
parent 925e35122e
commit 395124bd27
3 changed files with 24 additions and 5 deletions

View File

@ -1429,8 +1429,11 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
*/ */
if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) { if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) {
TouchListener *l; TouchListener *l;
GrabPtr g;
devgrab = dev->deviceGrab.grab; devgrab = dev->deviceGrab.grab;
g = AllocGrab(devgrab);
BUG_WARN(!g);
*dev->deviceGrab.sync.event = ev->device_event; *dev->deviceGrab.sync.event = ev->device_event;
@ -1439,8 +1442,8 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
* event selection. Thus, we update the last listener in the array. * event selection. Thus, we update the last listener in the array.
*/ */
l = &ti->listeners[ti->num_listeners - 1]; l = &ti->listeners[ti->num_listeners - 1];
l->listener = devgrab->resource; l->listener = g->resource;
l->grab = devgrab; l->grab = g;
//l->resource_type = RT_NONE; //l->resource_type = RT_NONE;
if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin) if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin)

View File

@ -1442,7 +1442,8 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
listener->type = LISTENER_POINTER_GRAB; listener->type = LISTENER_POINTER_GRAB;
else else
listener->type = LISTENER_GRAB; listener->type = LISTENER_GRAB;
listener->grab = grab; FreeGrab(listener->grab);
listener->grab = AllocGrab(grab);
} }
} }
} }

View File

@ -365,6 +365,8 @@ TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid,
void void
TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti) TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
{ {
int i;
if (ti->emulate_pointer) { if (ti->emulate_pointer) {
GrabPtr grab; GrabPtr grab;
@ -376,6 +378,9 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
} }
} }
for (i = 0; i < ti->num_listeners; i++)
TouchRemoveListener(ti, ti->listeners[0].listener);
ti->active = FALSE; ti->active = FALSE;
ti->pending_finish = FALSE; ti->pending_finish = FALSE;
ti->sprite.spriteTraceGood = 0; ti->sprite.spriteTraceGood = 0;
@ -692,15 +697,23 @@ void
TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type, TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type,
enum InputLevel level, enum TouchListenerType type, enum InputLevel level, enum TouchListenerType type,
enum TouchListenerState state, WindowPtr window, enum TouchListenerState state, WindowPtr window,
GrabPtr grab) const GrabPtr grab)
{ {
GrabPtr g = NULL;
/* We need a copy of the grab, not the grab itself since that may be
* deleted by a UngrabButton request and leaves us with a dangling
* pointer */
if (grab)
g = AllocGrab(grab);
ti->listeners[ti->num_listeners].listener = resource; ti->listeners[ti->num_listeners].listener = resource;
ti->listeners[ti->num_listeners].resource_type = resource_type; ti->listeners[ti->num_listeners].resource_type = resource_type;
ti->listeners[ti->num_listeners].level = level; ti->listeners[ti->num_listeners].level = level;
ti->listeners[ti->num_listeners].state = state; ti->listeners[ti->num_listeners].state = state;
ti->listeners[ti->num_listeners].type = type; ti->listeners[ti->num_listeners].type = type;
ti->listeners[ti->num_listeners].window = window; ti->listeners[ti->num_listeners].window = window;
ti->listeners[ti->num_listeners].grab = grab; ti->listeners[ti->num_listeners].grab = g;
if (grab) if (grab)
ti->num_grabs++; ti->num_grabs++;
ti->num_listeners++; ti->num_listeners++;
@ -725,6 +738,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
continue; continue;
if (listener->grab) { if (listener->grab) {
FreeGrab(listener->grab);
listener->grab = NULL; listener->grab = NULL;
ti->num_grabs--; ti->num_grabs--;
} }
@ -734,6 +748,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
ti->num_listeners--; ti->num_listeners--;
ti->listeners[ti->num_listeners].listener = 0; ti->listeners[ti->num_listeners].listener = 0;
ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN; ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;