Final audit: fix ghost-online, SQL injection, resource leak, NPE

CRITICAL-1/2: Remove duplicate online=1 writes from doPlayerJoin.
The synchronous onPlayerLoggedInKickCheck already sets online=1.
The background thread writes raced with logout's online=0, permanently
locking players as "online" after crash-disconnect during join.

HIGH-1: Startup SQL uses PreparedStatement for server_id (was string concat).
HIGH-2: update() method now uses try-with-resources for PreparedStatement.
HIGH-3: NPE guard in RS2 data file logging when getRS2DataFile returns null.

Vyrriox
This commit is contained in:
laforetbrut 2026-03-26 18:33:00 +01:00
parent b1563cc9ae
commit 484f1a8c05
4 changed files with 9 additions and 9 deletions

View File

@ -204,7 +204,7 @@ public class PlayerSync {
); );
try { try {
JDBCsetUp.executeUpdate("UPDATE player_data SET online=0 WHERE last_server=" + JdbcConfig.SERVER_ID.get() +" AND online=1 LIMIT 1000"); JDBCsetUp.executePreparedUpdate("UPDATE player_data SET online=0 WHERE last_server=? AND online=1 LIMIT 1000", JdbcConfig.SERVER_ID.get());
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("An exception occurred while trying change wrong player-status\n" + e.getMessage()); LOGGER.error("An exception occurred while trying change wrong player-status\n" + e.getMessage());
} }

View File

@ -269,12 +269,13 @@ public class VanillaSync {
} }
if (!playerExists) { if (!playerExists) {
// FIX CRITICAL-1/2: online=1 is already set by onPlayerLoggedInKickCheck (synchronous).
// Do NOT write online=1 again from background/queued threads - if the player disconnects
// quickly, the background write races with logout's online=0 and permanently locks the player.
server.execute(() -> { server.execute(() -> {
try { try {
new ModsSupport().doCuriosRestore(serverPlayer); new ModsSupport().doCuriosRestore(serverPlayer);
store(serverPlayer, true); store(serverPlayer, true); // INSERT with online=1 handled by store() init path
JDBCsetUp.executePreparedUpdate("UPDATE server_info SET last_update=? WHERE id=?", System.currentTimeMillis(), JdbcConfig.SERVER_ID.get());
JDBCsetUp.executePreparedUpdate("UPDATE player_data SET online=1, last_server=? WHERE uuid=?", JdbcConfig.SERVER_ID.get(), player_uuid);
serverPlayer.addTag("player_synced"); serverPlayer.addTag("player_synced");
} catch (Exception e) { } catch (Exception e) {
PlayerSync.LOGGER.error("Error initializing new player {}", player_uuid, e); PlayerSync.LOGGER.error("Error initializing new player {}", player_uuid, e);
@ -285,8 +286,7 @@ public class VanillaSync {
return; return;
} }
JDBCsetUp.executePreparedUpdate("UPDATE server_info SET last_update=? WHERE id=?", System.currentTimeMillis(), JdbcConfig.SERVER_ID.get()); // online=1 already set by onPlayerLoggedInKickCheck - no duplicate write here
JDBCsetUp.executePreparedUpdate("UPDATE player_data SET online=1, last_server=? WHERE uuid=?", JdbcConfig.SERVER_ID.get(), player_uuid);
// Read all DB data into local variables (background thread - safe) // Read all DB data into local variables (background thread - safe)
final int health, foodLevel, xp, score; final int health, foodLevel, xp, score;

View File

@ -462,7 +462,7 @@ public class ModsSupport {
// Read the .dat file directly (getDataFile is private, use reflection) // Read the .dat file directly (getDataFile is private, use reflection)
java.io.File datFile = getRS2DataFile(sp); java.io.File datFile = getRS2DataFile(sp);
if (datFile == null || !datFile.exists()) { if (datFile == null || !datFile.exists()) {
PlayerSync.LOGGER.warn("RS2 storage data file not found: {}", datFile.getAbsolutePath()); PlayerSync.LOGGER.warn("RS2 storage data file not found: {}", datFile != null ? datFile.getAbsolutePath() : "<null>");
return; return;
} }

View File

@ -90,8 +90,8 @@ public class JDBCsetUp {
*/ */
public static void update(String sql, String... argument) throws SQLException { public static void update(String sql, String... argument) throws SQLException {
LOGGER.trace(sql); LOGGER.trace(sql);
try (Connection connection = getConnection()) { // With database selected try (Connection connection = getConnection();
PreparedStatement updateStatement = connection.prepareStatement(sql); PreparedStatement updateStatement = connection.prepareStatement(sql)) {
for (int i = 0; i < argument.length; i++) { for (int i = 0; i < argument.length; i++) {
updateStatement.setString(i + 1, argument[i]); updateStatement.setString(i + 1, argument[i]);
} }