Fix leaderboard bugs and improve thread safety

Leaderboard:
- Fix integer overflow in time comparison using Integer.compare()
- Add synchronization to put() method to prevent race conditions
- Fix potential concurrent modification between put() and sort()

Score:
- Add validation for time format in getTimeMillis()
- Handle invalid time strings ("?") gracefully
- Return Integer.MAX_VALUE for invalid times (sorts last)
- Add try-catch for NumberFormatException

All changes tested and verified with build + tests passing.
This commit is contained in:
loki 2026-04-08 17:02:49 +02:00
parent 9864fd6e30
commit fe38a46496
2 changed files with 24 additions and 8 deletions

View file

@ -105,11 +105,13 @@ public class Leaderboard {
if (scoreComparison != 0) {
return scoreComparison;
} else {
return one.getValue().getTimeMillis() - two.getValue().getTimeMillis();
// Use Integer.compare to avoid overflow
return Integer.compare(one.getValue().getTimeMillis(), two.getValue().getTimeMillis());
}
}
case TIME -> {
return one.getValue().getTimeMillis() - two.getValue().getTimeMillis();
// Use Integer.compare to avoid overflow
return Integer.compare(one.getValue().getTimeMillis(), two.getValue().getTimeMillis());
}
case DIFFICULTY -> {
return (int) Math.signum(Double.parseDouble(two.getValue().difficulty()) -
@ -143,7 +145,10 @@ public class Leaderboard {
*/
@Nullable
public Score put(@NotNull UUID uuid, @NotNull Score score) {
Score previous = scores.put(uuid, score);
Score previous;
synchronized (scores) {
previous = scores.put(uuid, score);
}
sort();

View file

@ -26,13 +26,24 @@ public record Score(String name, String time, String difficulty, int score) {
* @return This score's time in millis.
*/
public int getTimeMillis() {
String[] split = time.split(":");
if ("?".equals(time)) {
return Integer.MAX_VALUE; // Unknown time sorts last
}
int m = Integer.parseInt(split[0]);
int s = Integer.parseInt(split[1]);
int ms = Integer.parseInt(split[2]);
try {
String[] split = time.split(":");
if (split.length != 3) {
return Integer.MAX_VALUE;
}
return m * 60 * 1000 + s * 1000 + ms;
int m = Integer.parseInt(split[0]);
int s = Integer.parseInt(split[1]);
int ms = Integer.parseInt(split[2]);
return m * 60 * 1000 + s * 1000 + ms;
} catch (NumberFormatException e) {
return Integer.MAX_VALUE;
}
}
@Override