diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2008-07-08 16:02:13 +0930 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2008-07-10 16:02:55 +0930 |
commit | acce27093571497a0626cee1cdb61ddf751dbc40 (patch) | |
tree | 82676a6dd2f5a03939cec42bf607b5bff9ae4109 /Xext/geext.c | |
parent | db86b8839f286e0e2efb5638b8ab2fe608707655 (diff) |
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.
Diffstat (limited to 'Xext/geext.c')
-rw-r--r-- | Xext/geext.c | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/Xext/geext.c b/Xext/geext.c index e49e71f66..171fda160 100644 --- a/Xext/geext.c +++ b/Xext/geext.c @@ -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); |