diff --git a/TCPServer.cpp b/TCPServer.cpp index 83073e5..e3ba0a8 100644 --- a/TCPServer.cpp +++ b/TCPServer.cpp @@ -123,6 +123,21 @@ namespace core { int TCPServer::processCommand(coreutils::ZString &request, TCPSession &session) { + // Was unguarded, like every other method below - `sessions` is + // mutated under `lock` by connectionRequest()/removeFromSessionList() + // (a session accepting or disconnecting on another thread), but + // every READ of it here had no lock at all. Confirmed live via + // dmesg: a real segfault at a stable, deterministic instruction + // offset (same crash signature as the Subscription::subscribers + // race fixed earlier this session, in SubscriptionManager.cpp) - + // Socket::write() -> resetSocket() dereferencing a null EPoll + // reference, consistent with iterating `sessions` while another + // thread concurrently erased and freed one of its entries. + // sendToAll() in particular is what most real gameplay broadcasts + // (combat, position, chat) go through, so this is very likely the + // actual dominant cause of that crash, not just the ItemDataBase + // subscriber list this session's earlier fix addressed. + std::lock_guard guard(lock); int sequence = 0; for (auto *sessionx : sessions) { @@ -134,12 +149,14 @@ namespace core { } void TCPServer::sendToAll(std::stringstream &data) { + std::lock_guard guard(lock); for (auto session : sessions) session->write(data.str()); data.str(""); } void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender) { + std::lock_guard guard(lock); for (auto session : sessions) if (session != &sender) session->write(data.str()); @@ -147,6 +164,7 @@ namespace core { } void TCPServer::sendToAll(std::stringstream &data, TCPSession &sender, SessionFilter filter) { + std::lock_guard guard(lock); for (auto session : sessions) if (filter.test(*session)) if (session != &sender) @@ -156,6 +174,7 @@ namespace core { TCPSession *TCPServer::getSessionByAlias(void *alias) { coreutils::Log(coreutils::LOG_DEBUG_1) << alias; + std::lock_guard guard(lock); for (auto session : sessions) if (session->alias == alias) return session;