From 0f3597e7f313bbc231817172b9786cbfe2e974d0 Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Tue, 16 Jun 2009 20:57:43 -0700 Subject: [PATCH] Bug 22084: XFS server crash with many dropped connections http://bugs.freedesktop.org/show_bug.cgi?id=22084 Fixes three crashes I hit investigating this report: 1) Replace ffs() with a version that handles fd_mask sized arguments instead of int sized ones, so we don't get stuck in 64-bit builds when fd bits are set past the 32-bit boundary. (os/WaitFor.c in the X server already does this.) 2) Check that the client OsPrivate isn't already NULL before dismantling it in CloseDownConnection() 3) Make sure we aren't overflowing the pClientsReady buffer when returning the list of clients ready for processing. Signed-off-by: Alan Coopersmith --- os/connection.c | 3 +++ os/waitfor.c | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletions(-) diff --git a/os/connection.c b/os/connection.c index 511a780..bc35a60 100644 --- a/os/connection.c +++ b/os/connection.c @@ -470,6 +470,9 @@ CloseDownConnection(ClientPtr client) { OsCommPtr oc = (OsCommPtr) client->osPrivate; + if (oc == NULL) + return; + if (oc->output && oc->output->count) FlushClient(client, oc, (char *) NULL, 0, 0); ConnectionTranslation[oc->fd] = 0; diff --git a/os/waitfor.c b/os/waitfor.c index 512f537..98fbe8a 100644 --- a/os/waitfor.c +++ b/os/waitfor.c @@ -70,6 +70,23 @@ in this Software without prior written authorization from The Open Group. long LastReapTime; +/* like ffs, but uses fd_mask instead of int as argument, so it works + when fd_mask is longer than an int, such as common 64-bit platforms */ +static inline int +xfd_ffs(fd_mask mask) +{ + int i; + + if (!mask) return 0; + + for (i = 1; !(mask & 1); i++) + { + mask >>= 1; + } + return i; +} + + /* * wait_for_something * @@ -179,7 +196,7 @@ WaitForSomething(int *pClientsReady) current_time = GetTimeInMillis(); for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { while (clientsReadable.fds_bits[i]) { - curclient = ffs(clientsReadable.fds_bits[i]) - 1; + curclient = xfd_ffs(clientsReadable.fds_bits[i]) - 1; conn = ConnectionTranslation[curclient + (i << 5)]; clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); client = clients[conn]; @@ -188,6 +205,12 @@ WaitForSomething(int *pClientsReady) pClientsReady[nready++] = conn; client->last_request_time = current_time; client->clientGone = CLIENT_ALIVE; + + if (nready >= MaxClients) { + /* pClientsReady buffer has no more room, get the + rest on the next time through select() loop */ + return nready; + } } } } -- 1.5.6.5