Commit acce2709 authored by Peter Hutterer's avatar Peter Hutterer

Xext: store the GenericMasks in the resource system.

This fixes a severe issue - when the client died the event mask didn't get
unregistered and a future event would dereference dangling pointers. By
storing the event masks in the resource system we can free them when the
client dies.
parent db86b883
......@@ -36,12 +36,15 @@
#define SERVER_GE_MAJOR 1
#define SERVER_GE_MINOR 0
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
int GEEventBase;
int GEErrorBase;
DevPrivateKey GEClientPrivateKey = &GEClientPrivateKey;
int GEEventType; /* The opcode for all GenericEvents will have. */
int RT_GECLIENT = 0;
GEExtension GEExtensions[MAXEXTENSIONS];
......@@ -53,6 +56,7 @@ static const int version_requests[] = {
/* Forward declarations */
static void SGEGenericEvent(xEvent* from, xEvent* to);
static void GERecalculateWinMask(WindowPtr pWin);
#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
......@@ -211,6 +215,43 @@ SGEGenericEvent(xEvent* from, xEvent* to)
GEExtensions[gefrom->extension & 0x7F].evswap(gefrom, geto);
}
/**
* Resource callback, invoked when the client disconnects and the associated
* GE masks must be destroyed.
*/
int
GEClientGone(WindowPtr pWin, XID id)
{
GenericClientMasksPtr gclmask;
GenericMaskPtr gmask, prev = NULL;
if (!pWin || !pWin->optional)
return Success;
gclmask = pWin->optional->geMasks;
for (gmask = gclmask->geClients; gmask; gmask = gmask->next)
{
if (gmask->resource == id)
{
if (prev)
{
prev->next = gmask->next;
xfree(gmask);
} else {
gclmask->geClients = NULL;
CheckWindowOptionalNeed(pWin);
GERecalculateWinMask(pWin);
xfree(gmask);
}
return Success;
}
prev = gmask;
}
FatalError("Client not a GE client");
return BadImplementation;
}
/* Init extension, register at server.
* Since other extensions may rely on XGE (XInput does already), it is a good
* idea to init XGE first, before any other extension.
......@@ -234,6 +275,9 @@ GEExtensionInit(void)
GEErrorBase = extEntry->errorBase;
GEEventType = GEEventBase;
RT_GECLIENT = CreateNewResourceType((DeleteType)GEClientGone);
RegisterResourceName(RT_GECLIENT, "GECLIENT");
memset(GEExtensions, 0, sizeof(GEExtensions));
EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent;
......@@ -338,7 +382,7 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
cli = evmasks->geClients;
while(cli)
{
if (cli->client == pClient && cli->dev == pDev)
if (rClient(cli) == pClient && cli->dev == pDev)
break;
cli = cli->next;
}
......@@ -352,16 +396,17 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
return;
}
cli->next = evmasks->geClients;
cli->client = pClient;
cli->resource = FakeClientID(pClient->index);
cli->dev = pDev;
evmasks->geClients = cli;
AddResource(cli->resource, RT_GECLIENT, (pointer)pWin);
}
cli->eventMask[extension] = mask;
} else
{
/* remove client. */
cli = pWin->optional->geMasks->geClients;
if (cli->client == pClient && cli->dev == pDev)
if (rClient(cli) == pClient && cli->dev == pDev)
{
pWin->optional->geMasks->geClients = cli->next;
xfree(cli);
......@@ -372,7 +417,7 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
while(cli)
{
if (cli->client == pClient && cli->dev == pDev)
if (rClient(cli) == pClient && cli->dev == pDev)
{
prev->next = cli->next;
xfree(cli);
......
......@@ -43,10 +43,10 @@ from the author.
* A grab has only one instance of this struct.
*/
typedef struct _GenericMaskRec {
ClientPtr client; /* client who set the event mask */
struct _GenericMaskRec* next;
XID resource; /* id for the resource manager */
DeviceIntPtr dev;
Mask eventMask[MAXEXTENSIONS]; /* one mask per extension */
struct _GenericMaskRec* next;
} GenericMaskRec, *GenericMaskPtr;
......
......@@ -175,7 +175,7 @@ ProcXExtendedGrabDevice(ClientPtr client)
(XGenericEventMask*)(((XEventClass*)&stuff[1]) + stuff->event_count);
gemasks = xcalloc(1, sizeof(GenericMaskRec));
gemasks->client = client;
gemasks->resource = FakeClientID(client->index);
gemasks->next = NULL;
gemasks->eventMask[xgeMask->extension & 0x7F] = xgeMask->evmask;
......
......@@ -2118,7 +2118,7 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
/* Handle generic events */
if (type == GenericEvent)
{
GenericMaskPtr pClient;
GenericMaskPtr gmask;
/* We don't do more than one GenericEvent at a time. */
if (count > 1)
{
......@@ -2132,16 +2132,16 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
return 0;
/* run through all clients, deliver event */
for (pClient = GECLIENT(pWin); pClient; pClient = pClient->next)
for (gmask = GECLIENT(pWin); gmask; gmask = gmask->next)
{
if (pClient->eventMask[GEEXTIDX(pEvents)] & filter)
if (gmask->eventMask[GEEXTIDX(pEvents)] & filter)
{
if (XaceHook(XACE_RECEIVE_ACCESS, pClient->client, pWin,
if (XaceHook(XACE_RECEIVE_ACCESS, rClient(gmask), pWin,
pEvents, count))
/* do nothing */;
else if (TryClientEvents(pClient->client, pDev,
else if (TryClientEvents(rClient(gmask), pDev,
pEvents, count,
pClient->eventMask[GEEXTIDX(pEvents)],
gmask->eventMask[GEEXTIDX(pEvents)],
filter, grab) > 0)
{
deliveries++;
......@@ -2223,7 +2223,7 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
{
GenericClientMasksPtr gemasks = pWin->optional->geMasks;
GenericMaskPtr geclient = gemasks->geClients;
while(geclient && geclient->client != client)
while(geclient && rClient(geclient) != client)
geclient = geclient->next;
if (geclient)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment