Fix lock inversion in processEventsWhileBlocked

Former-commit-id: a9249d4a82a0f0355ac8ffa40b34b9c14cabf66b
This commit is contained in:
John Sully 2020-03-19 15:28:39 -04:00
parent 87626299a6
commit 4d5d7ed59f

View File

@ -1630,12 +1630,12 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
if (writeToClient(fd,c,1) == C_ERR) if (writeToClient(fd,c,1) == C_ERR)
{ {
AeLocker ae; AeLocker ae;
c->lock(); c->lock.lock();
ae.arm(c); ae.arm(c);
if (c->flags & CLIENT_CLOSE_ASAP) if (c->flags & CLIENT_CLOSE_ASAP)
{ {
if (!freeClient(c)) if (!freeClient(c))
c->unlock(); c->lock.unlock();
} }
} }
} }
@ -3107,13 +3107,24 @@ int processEventsWhileBlocked(int iel) {
int iterations = 4; /* See the function top-comment. */ int iterations = 4; /* See the function top-comment. */
int count = 0; int count = 0;
client *c = serverTL->current_client; std::vector<client*> vecclients;
if (c != nullptr) listIter li;
listNode *ln;
listRewind(g_pserver->clients, &li);
// All client locks must be acquired *after* the global lock is reacquired to prevent deadlocks
// so unlock here, and save them for reacquisition later
while ((ln = listNext(&li)) != nullptr)
{ {
serverAssert(c->flags & CLIENT_PROTECTED); client *c = (client*)listNodeValue(ln);
c->lock.unlock(); if (c->lock.fOwnLock()) {
serverAssert(c->flags & CLIENT_PROTECTED); // If the client is not protected we have no gurantee they won't be free'd in the event loop
c->lock.unlock();
vecclients.push_back(c);
}
} }
aeReleaseLock(); aeReleaseLock();
try try
{ {
@ -3129,18 +3140,18 @@ int processEventsWhileBlocked(int iel) {
{ {
// Caller expects us to be locked so fix and rethrow // Caller expects us to be locked so fix and rethrow
AeLocker locker; AeLocker locker;
if (c != nullptr) locker.arm(nullptr);
c->lock.lock();
locker.arm(c);
locker.release(); locker.release();
for (client *c : vecclients)
c->lock.lock();
throw; throw;
} }
AeLocker locker; AeLocker locker;
if (c != nullptr) locker.arm(nullptr);
c->lock.lock();
locker.arm(c);
locker.release(); locker.release();
for (client *c : vecclients)
c->lock.lock();
return count; return count;
} }