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)
{
AeLocker ae;
c->lock();
c->lock.lock();
ae.arm(c);
if (c->flags & CLIENT_CLOSE_ASAP)
{
if (!freeClient(c))
c->unlock();
c->lock.unlock();
}
}
}
@ -3107,12 +3107,23 @@ int processEventsWhileBlocked(int iel) {
int iterations = 4; /* See the function top-comment. */
int count = 0;
client *c = serverTL->current_client;
if (c != nullptr)
std::vector<client*> vecclients;
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);
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();
try
@ -3129,18 +3140,18 @@ int processEventsWhileBlocked(int iel) {
{
// Caller expects us to be locked so fix and rethrow
AeLocker locker;
if (c != nullptr)
c->lock.lock();
locker.arm(c);
locker.arm(nullptr);
locker.release();
for (client *c : vecclients)
c->lock.lock();
throw;
}
AeLocker locker;
if (c != nullptr)
c->lock.lock();
locker.arm(c);
locker.arm(nullptr);
locker.release();
for (client *c : vecclients)
c->lock.lock();
return count;
}