fix: dedicated server thread safety, disconnect deadlock, and console freeze

- Protect PlayerList and ServerConnection players vectors with critical
  sections; all iterations use copy-on-read snapshots to prevent iterator
  invalidation during concurrent join/leave
- Add null check on player bounding box in movement validation to prevent
  crash when player is removed mid-tick
- Re-validate socket player pointer immediately before SendData to narrow
  the TOCTOU race window on disconnect
- Replace inline disconnect cleanup with a queued system drained on the
  main tick thread, eliminating the done_cs -> m_playersCS lock inversion
  that caused deadlocks under load
- Disable Windows QuickEdit mode at server startup to prevent console
  input selection from freezing the process
- Move chunk priority sort behind ServerConnection::sortPlayersByChunkPriority()
  to keep the players vector lock-protected
This commit is contained in:
itsRevela
2026-04-10 01:12:59 -05:00
parent 055bce517d
commit 20229fc07b
9 changed files with 309 additions and 158 deletions
+16
View File
@@ -24,11 +24,26 @@ private:
// public static Logger logger = Logger.getLogger("Minecraft");
public:
vector<shared_ptr<ServerPlayer> > players;
CRITICAL_SECTION m_playersCS; // Protects players vector for concurrent access
vector<shared_ptr<ServerPlayer> > getPlayersSnapshot();
private:
MinecraftServer *server;
unsigned int maxPlayers;
// Pending disconnect queue: disconnect() enqueues here, tick() drains it.
// This avoids holding done_cs across PlayerList operations (deadlock fix).
struct PendingDisconnect
{
shared_ptr<ServerPlayer> player;
int reason;
wstring kickMessage;
bool wasKicked;
bool fourKitHandledQuit;
};
deque<PendingDisconnect> m_pendingDisconnects;
CRITICAL_SECTION m_disconnectCS;
// 4J Added
vector<PlayerUID> m_bannedXuids;
CRITICAL_SECTION m_banCS; // 4J Added - protects m_bannedXuids for concurrent access
@@ -82,6 +97,7 @@ public:
void add(shared_ptr<ServerPlayer> player);
void move(shared_ptr<ServerPlayer> player);
void remove(shared_ptr<ServerPlayer> player);
void queueDisconnect(shared_ptr<ServerPlayer> player, int reason, const wstring& kickMessage, bool wasKicked, bool fourKitHandledQuit);
shared_ptr<ServerPlayer> getPlayerForLogin(PendingConnection *pendingConnection, const wstring& userName, PlayerUID xuid, PlayerUID OnlineXuid);
shared_ptr<ServerPlayer> respawn(shared_ptr<ServerPlayer> serverPlayer, int targetDimension, bool keepAllPlayerData);
void toggleDimension(shared_ptr<ServerPlayer> player, int targetDimension);