summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2010-05-01 13:07:46 -0400
committerKristian Høgsberg <krh@bitplanet.net>2010-05-11 11:01:34 -0400
commit6d7ba5e0fcb5d1bce6bb213dec009f3a0f802d26 (patch)
treeb6016aed642ed085d6cda67985fbba1113ed8196
parent10de9e8ee37265a35ceeceb2007d711da70d4f2d (diff)
dix: Update element count in FreeResource*()
FreeResource() keeps clientTable[cid].elements up to date with the number of resources allocated to the client. The other free resource functions (FreeResourceByType(), FreeClientNeverRetainResources() and FreeClientResources()) don't maintain this invariant. Typically, the only consequence is that the element count is too high and we end up allocating the hash table bigger than necessary. However, FreeResource() also relies on the element count to restart the search if the list of resources has been changed during a resource destruction callback. Since FreeResourceByType() doesn't update the count, if we call that from a resource destruction callback from FreeResource(), the loop isn't restarted and we end up following an invalid next pointer. Furthermore, LookupClientResourceComplex() and FreeClientNeverRetainResources() don't use the element count to detect if a callback deleted a resource and may end up following an invalid next pointer if the resource system is called into recursively. Signed-off-by: Kristian Høgsberg <krh@bitplanet.net> Reviewed-by: Keith Packard <keithp@keithp.com>
-rw-r--r--dix/resource.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/dix/resource.c b/dix/resource.c
index 91d0cfb1c..ab3762eb5 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -589,6 +589,7 @@ FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
res->value, TypeNameString(res->type));
#endif
*prev = res->next;
+ clientTable[cid].elements--;
CallResourceStateCallback(ResourceStateFreeing, res);
@@ -734,12 +735,14 @@ FreeClientNeverRetainResources(ClientPtr client)
ResourcePtr *resources;
ResourcePtr this;
ResourcePtr *prev;
- int j;
+ int j, elements;
+ int *eltptr;
if (!client)
return;
resources = clientTable[client->index].resources;
+ eltptr = &clientTable[client->index].elements;
for (j=0; j < clientTable[client->index].buckets; j++)
{
prev = &resources[j];
@@ -753,11 +756,15 @@ FreeClientNeverRetainResources(ClientPtr client)
this->value, TypeNameString(this->type));
#endif
*prev = this->next;
+ clientTable[client->index].elements--;
CallResourceStateCallback(ResourceStateFreeing, this);
+ elements = *eltptr;
(*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
xfree(this);
+ if (*eltptr != elements)
+ prev = &resources[j]; /* prev may no longer be valid */
}
else
prev = &this->next;
@@ -804,6 +811,7 @@ FreeClientResources(ClientPtr client)
this->value, TypeNameString(this->type));
#endif
*head = this->next;
+ clientTable[client->index].elements--;
CallResourceStateCallback(ResourceStateFreeing, this);