Skip to content

Commit

Permalink
Fix StackOverflowException thrown on shutdown (Fixes #10404) (#10408)
Browse files Browse the repository at this point in the history
paper previously migrated away from using executeIfPossible as this throws a
RejectedExecutionException when the server is shutting down, which is then picked
up by the Connection handler object and causes the player to be kicked without
the intended disconnection message that comes from commands such as /stop, /restart

This was fine, because previously changes made in spigot would just prevent these
packets from being executed anyways. Instead, we'll just use a marker exception
to try to detect this specific state.
  • Loading branch information
electronicboy authored Apr 12, 2024
1 parent 8fe90de commit 46d462b
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 40 deletions.
23 changes: 0 additions & 23 deletions patches/server/0818-Fix-player-kick-on-shutdown.patch

This file was deleted.

61 changes: 61 additions & 0 deletions patches/server/0818-Fix-premature-player-kicks-on-shutdown.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <[email protected]>
Date: Thu, 11 Apr 2024 16:37:44 +0100
Subject: [PATCH] Fix premature player kicks on shutdown

When the server is stopping, the default execution handler method will throw a
RejectedExecutionException in order to prevent further execution, this causes
us to lose the actual kick reason. To mitigate this, we'll use a seperate marked
class in order to gracefully ignore these.

diff --git a/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c5cd77103c5a33d4349ab6b9ee2d8378bb60eb4
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java
@@ -0,0 +1,20 @@
+package io.papermc.paper.util;
+
+import java.util.concurrent.RejectedExecutionException;
+
+public class ServerStopRejectedExecutionException extends RejectedExecutionException {
+ public ServerStopRejectedExecutionException() {
+ }
+
+ public ServerStopRejectedExecutionException(final String message) {
+ super(message);
+ }
+
+ public ServerStopRejectedExecutionException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ public ServerStopRejectedExecutionException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 22a7f17180b76b6c3548d3b54ae8218a469401a8..c399625a342ffd61102bb96a97ac24b0669e8e17 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -290,6 +290,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
Connection.genericsFtw(packet, packetlistener);
} catch (RunningOnDifferentThreadException cancelledpackethandleexception) {
;
+ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop
} catch (RejectedExecutionException rejectedexecutionexception) {
this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
} catch (ClassCastException classcastexception) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index bfee202e1dc8ea875b9d2b4e8c3b0be3f6d94b26..d50d3bc9c0f573cdb43100bce6e3dbfe2102fc53 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -2013,7 +2013,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@Override
public void executeIfPossible(Runnable runnable) {
if (this.isStopped()) {
- throw new RejectedExecutionException("Server already shutting down");
+ throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop
} else {
super.executeIfPossible(runnable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ and then catch exceptions and close if they fire.
Part of this commit was authored by: Spottedleaf, sandtechnology

diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca68b188eb9 100644
index c399625a342ffd61102bb96a97ac24b0669e8e17..16eb94eb1f40485daef2713f740f6e0beeb1463f 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -84,7 +84,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
Expand All @@ -51,7 +51,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6

// Paper start - add utility methods
public final net.minecraft.server.level.ServerPlayer getPlayer() {
@@ -375,15 +379,39 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -376,15 +380,39 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}

public void send(Packet<?> packet, @Nullable PacketSendListener callbacks, boolean flush) {
Expand Down Expand Up @@ -97,7 +97,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
}

public void runOnceConnected(Consumer<Connection> task) {
@@ -391,7 +419,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -392,7 +420,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
this.flushQueue();
task.accept(this);
} else {
Expand All @@ -106,7 +106,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
}

}
@@ -409,6 +437,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -410,6 +438,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}

private void doSendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks, boolean flush) {
Expand All @@ -121,7 +121,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
ChannelFuture channelfuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet);

if (callbacks != null) {
@@ -428,14 +464,24 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -429,14 +465,24 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
});
}

Expand All @@ -147,7 +147,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
}

}
@@ -468,20 +514,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -469,20 +515,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return attributekey;
}

Expand Down Expand Up @@ -212,15 +212,15 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6

private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
@@ -544,6 +627,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -545,6 +628,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void disconnect(Component disconnectReason) {
// Spigot Start
this.preparing = false;
+ this.clearPacketQueue(); // Paper - Optimize network
// Spigot End
if (this.channel == null) {
this.delayedDisconnect = disconnectReason;
@@ -715,7 +799,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -716,7 +800,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void handleDisconnection() {
if (this.channel != null && !this.channel.isOpen()) {
if (this.disconnectionHandled) {
Expand All @@ -229,7 +229,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
} else {
this.disconnectionHandled = true;
PacketListener packetlistener = this.getPacketListener();
@@ -728,7 +812,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -729,7 +813,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {

packetlistener1.onDisconnect(ichatbasecomponent);
}
Expand All @@ -238,7 +238,7 @@ index 22a7f17180b76b6c3548d3b54ae8218a469401a8..7f2aa5e17fe675f3404d67b1794d2ca6
// Paper start - Add PlayerConnectionCloseEvent
final PacketListener packetListener = this.getPacketListener();
if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
@@ -765,4 +849,93 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -766,4 +850,93 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setBandwidthLogger(SampleLogger log) {
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(log);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,10 @@ index 11a466558c77b43969b8e4be3a3470f84c7fcb1a..ae6e8ab9c1afa31d808f1fce2654a8b9
}

diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 7f2aa5e17fe675f3404d67b1794d2ca68b188eb9..fff375fd50fa1a804636a92ded1ae55cff42977d 100644
index 16eb94eb1f40485daef2713f740f6e0beeb1463f..fae2a57570a4007b67b9949b9b16504da36a9886 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -734,11 +734,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -735,11 +735,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return networkmanager;
}

Expand Down Expand Up @@ -296,7 +296,7 @@ index 7f2aa5e17fe675f3404d67b1794d2ca68b188eb9..fff375fd50fa1a804636a92ded1ae55c

public boolean isEncrypted() {
return this.encrypted;
@@ -771,16 +788,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -772,16 +789,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {

public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
if (compressionThreshold >= 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ Subject: [PATCH] Detail more information in watchdog dumps
- Dump player name, player uuid, position, and world for packet handling

diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index fff375fd50fa1a804636a92ded1ae55cff42977d..4716f8bd8a64d4f20f0d5957c1e7fabf63020f43 100644
index fae2a57570a4007b67b9949b9b16504da36a9886..a536ebcf29d8ef0ed32863bd8d5e70f7a0636e8d 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -586,7 +586,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -587,7 +587,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
Expand All @@ -25,7 +25,7 @@ index fff375fd50fa1a804636a92ded1ae55cff42977d..4716f8bd8a64d4f20f0d5957c1e7fabf
// Paper end - Buffer joins to world
}
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
index 4202c48ad8f8e85ef46d1bd446ab28f3f4b083d1..32838f87978c0694bdb573236b7cdf72b2e363cd 100644
index b7ffab0284b0bccd79775b8d03c8b2e088f91d1d..83302c252f54481f239522e5c6861ccfe233070a 100644
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
@@ -18,6 +18,24 @@ public class PacketUtils {
Expand Down Expand Up @@ -56,7 +56,7 @@ index 4202c48ad8f8e85ef46d1bd446ab28f3f4b083d1..32838f87978c0694bdb573236b7cdf72
@@ -27,6 +45,8 @@ public class PacketUtils {
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, BlockableEventLoop<?> engine) throws RunningOnDifferentThreadException {
if (!engine.isSameThread()) {
engine.execute(() -> { // Paper - Fix preemptive player kick on a server shutdown
engine.executeIfPossible(() -> {
+ packetProcessing.push(listener); // Paper - detailed watchdog information
+ try { // Paper - detailed watchdog information
if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players
Expand Down

0 comments on commit 46d462b

Please sign in to comment.