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.
This commit is contained in:
Peter Hutterer 2008-07-08 16:02:13 +09:30
parent db86b8839f
commit acce270935
4 changed files with 59 additions and 14 deletions

View File

@ -36,12 +36,15 @@
#define SERVER_GE_MAJOR 1 #define SERVER_GE_MAJOR 1
#define SERVER_GE_MINOR 0 #define SERVER_GE_MINOR 0
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
int GEEventBase; int GEEventBase;
int GEErrorBase; int GEErrorBase;
DevPrivateKey GEClientPrivateKey = &GEClientPrivateKey; DevPrivateKey GEClientPrivateKey = &GEClientPrivateKey;
int GEEventType; /* The opcode for all GenericEvents will have. */ int GEEventType; /* The opcode for all GenericEvents will have. */
int RT_GECLIENT = 0;
GEExtension GEExtensions[MAXEXTENSIONS]; GEExtension GEExtensions[MAXEXTENSIONS];
@ -53,6 +56,7 @@ static const int version_requests[] = {
/* Forward declarations */ /* Forward declarations */
static void SGEGenericEvent(xEvent* from, xEvent* to); static void SGEGenericEvent(xEvent* from, xEvent* to);
static void GERecalculateWinMask(WindowPtr pWin);
#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) #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); 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. /* Init extension, register at server.
* Since other extensions may rely on XGE (XInput does already), it is a good * Since other extensions may rely on XGE (XInput does already), it is a good
* idea to init XGE first, before any other extension. * idea to init XGE first, before any other extension.
@ -234,6 +275,9 @@ GEExtensionInit(void)
GEErrorBase = extEntry->errorBase; GEErrorBase = extEntry->errorBase;
GEEventType = GEEventBase; GEEventType = GEEventBase;
RT_GECLIENT = CreateNewResourceType((DeleteType)GEClientGone);
RegisterResourceName(RT_GECLIENT, "GECLIENT");
memset(GEExtensions, 0, sizeof(GEExtensions)); memset(GEExtensions, 0, sizeof(GEExtensions));
EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent; EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent;
@ -338,7 +382,7 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
cli = evmasks->geClients; cli = evmasks->geClients;
while(cli) while(cli)
{ {
if (cli->client == pClient && cli->dev == pDev) if (rClient(cli) == pClient && cli->dev == pDev)
break; break;
cli = cli->next; cli = cli->next;
} }
@ -352,16 +396,17 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
return; return;
} }
cli->next = evmasks->geClients; cli->next = evmasks->geClients;
cli->client = pClient; cli->resource = FakeClientID(pClient->index);
cli->dev = pDev; cli->dev = pDev;
evmasks->geClients = cli; evmasks->geClients = cli;
AddResource(cli->resource, RT_GECLIENT, (pointer)pWin);
} }
cli->eventMask[extension] = mask; cli->eventMask[extension] = mask;
} else } else
{ {
/* remove client. */ /* remove client. */
cli = pWin->optional->geMasks->geClients; 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; pWin->optional->geMasks->geClients = cli->next;
xfree(cli); xfree(cli);
@ -372,7 +417,7 @@ GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
while(cli) while(cli)
{ {
if (cli->client == pClient && cli->dev == pDev) if (rClient(cli) == pClient && cli->dev == pDev)
{ {
prev->next = cli->next; prev->next = cli->next;
xfree(cli); xfree(cli);

View File

@ -43,10 +43,10 @@ from the author.
* A grab has only one instance of this struct. * A grab has only one instance of this struct.
*/ */
typedef struct _GenericMaskRec { typedef struct _GenericMaskRec {
ClientPtr client; /* client who set the event mask */ struct _GenericMaskRec* next;
XID resource; /* id for the resource manager */
DeviceIntPtr dev; DeviceIntPtr dev;
Mask eventMask[MAXEXTENSIONS]; /* one mask per extension */ Mask eventMask[MAXEXTENSIONS]; /* one mask per extension */
struct _GenericMaskRec* next;
} GenericMaskRec, *GenericMaskPtr; } GenericMaskRec, *GenericMaskPtr;

View File

@ -175,7 +175,7 @@ ProcXExtendedGrabDevice(ClientPtr client)
(XGenericEventMask*)(((XEventClass*)&stuff[1]) + stuff->event_count); (XGenericEventMask*)(((XEventClass*)&stuff[1]) + stuff->event_count);
gemasks = xcalloc(1, sizeof(GenericMaskRec)); gemasks = xcalloc(1, sizeof(GenericMaskRec));
gemasks->client = client; gemasks->resource = FakeClientID(client->index);
gemasks->next = NULL; gemasks->next = NULL;
gemasks->eventMask[xgeMask->extension & 0x7F] = xgeMask->evmask; gemasks->eventMask[xgeMask->extension & 0x7F] = xgeMask->evmask;

View File

@ -2118,7 +2118,7 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
/* Handle generic events */ /* Handle generic events */
if (type == GenericEvent) if (type == GenericEvent)
{ {
GenericMaskPtr pClient; GenericMaskPtr gmask;
/* We don't do more than one GenericEvent at a time. */ /* We don't do more than one GenericEvent at a time. */
if (count > 1) if (count > 1)
{ {
@ -2132,16 +2132,16 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
return 0; return 0;
/* run through all clients, deliver event */ /* 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)) pEvents, count))
/* do nothing */; /* do nothing */;
else if (TryClientEvents(pClient->client, pDev, else if (TryClientEvents(rClient(gmask), pDev,
pEvents, count, pEvents, count,
pClient->eventMask[GEEXTIDX(pEvents)], gmask->eventMask[GEEXTIDX(pEvents)],
filter, grab) > 0) filter, grab) > 0)
{ {
deliveries++; deliveries++;
@ -2223,7 +2223,7 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
{ {
GenericClientMasksPtr gemasks = pWin->optional->geMasks; GenericClientMasksPtr gemasks = pWin->optional->geMasks;
GenericMaskPtr geclient = gemasks->geClients; GenericMaskPtr geclient = gemasks->geClients;
while(geclient && geclient->client != client) while(geclient && rClient(geclient) != client)
geclient = geclient->next; geclient = geclient->next;
if (geclient) if (geclient)
{ {