2020-05-06 09:48:49 +00:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2016-01-13 05:00:58 +00:00
From: Aikar <aikar@aikar.co>
2016-02-29 23:09:49 +00:00
Date: Thu, 3 Mar 2016 01:17:12 -0600
2016-01-13 05:00:58 +00:00
Subject: [PATCH] Ensure commands are not ran async
Plugins calling Player.chat("/foo") or Server.dispatchCommand() could
trigger the server to execute a command while on another thread.
These commands would then process EXPECTING to be on the main thread, leaving to
very hard to trace concurrency issues.
This change will synchronize the command execution back to the main thread, causing a
big slowdown in execution but throwing an exception at same time to raise awareness
that it is happening so that plugin authors can fix their code to stop executing commands async.
2021-03-16 07:19:45 +00:00
diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java
2021-04-18 09:02:48 +00:00
index a39f58e0c60b5e3ccc3b725f1f4167d52b230e11..6a8567c355202560ee523c6dc68cac1ac3e562fd 100644
2021-03-16 07:19:45 +00:00
--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java
2021-04-18 09:02:48 +00:00
@@ -1853,6 +1853,29 @@ public class PlayerConnection implements PacketListenerPlayIn {
2016-01-13 05:00:58 +00:00
}
if (!async && s.startsWith("/")) {
2016-02-29 23:09:49 +00:00
+ // Paper Start
2018-02-15 05:34:58 +00:00
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) {
2016-01-13 05:00:58 +00:00
+ final String fCommandLine = s;
+ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine);
+ MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ Waitable wait = new Waitable() {
+ @Override
+ protected Object evaluate() {
+ chat(fCommandLine, false);
+ return null;
+ }
+ };
+ minecraftServer.processQueue.add(wait);
+ try {
+ wait.get();
+ return;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing chat command", e.getCause());
+ }
+ }
2016-02-29 23:09:49 +00:00
+ // Paper End
2016-01-13 05:00:58 +00:00
this.handleCommand(s);
2019-04-25 06:53:51 +00:00
} else if (this.player.getChatFlags() == EnumChatVisibility.SYSTEM) {
2016-01-13 05:00:58 +00:00
// Do nothing, this is coming from a plugin
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2021-03-16 07:19:45 +00:00
index f84fe5929cb7bcedff5fc587163380172bc1e8be..8e9547fc745e8244ca1f439770571ca1175ff632 100644
2016-01-13 05:00:58 +00:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2021-02-21 20:55:01 +00:00
@@ -762,6 +762,29 @@ public final class CraftServer implements Server {
2016-01-13 05:00:58 +00:00
Validate.notNull(commandLine, "CommandLine cannot be null");
2019-07-23 19:17:32 +00:00
org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
2016-01-13 05:00:58 +00:00
2016-02-29 23:09:49 +00:00
+ // Paper Start
2018-02-15 05:34:58 +00:00
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) {
2016-01-13 05:00:58 +00:00
+ final CommandSender fSender = sender;
+ final String fCommandLine = commandLine;
+ Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine);
+ Bukkit.getLogger().log(Level.SEVERE, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ org.bukkit.craftbukkit.util.Waitable<Boolean> wait = new org.bukkit.craftbukkit.util.Waitable<Boolean>() {
+ @Override
+ protected Boolean evaluate() {
+ return dispatchCommand(fSender, fCommandLine);
+ }
+ };
+ net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait);
+ try {
+ return wait.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing dispatch command", e.getCause());
+ }
+ }
2016-02-29 23:09:49 +00:00
+ // Paper End
2016-01-13 05:00:58 +00:00
+
if (commandMap.dispatch(sender, commandLine)) {
return true;
}
2018-02-15 05:34:58 +00:00
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
2020-05-06 09:48:49 +00:00
index ddef523ea8762c927f37f7d16d581e43367e8c6b..70f8d42992aa348ef7b2d03d22cdd59d7c73f0fe 100644
2018-02-15 05:34:58 +00:00
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
2019-04-25 06:53:51 +00:00
@@ -13,6 +13,7 @@ public class ServerShutdownThread extends Thread {
2018-02-15 05:34:58 +00:00
public void run() {
try {
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
2019-04-25 06:53:51 +00:00
server.close();
} finally {
try {
2018-02-15 05:34:58 +00:00
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
2020-05-06 09:48:49 +00:00
index aeed7697254af17ffefe8e578353ad216e15f9f3..9f7d2ef932ab41cef5d3d0736d20a7c7e4a2c888 100644
2018-02-15 05:34:58 +00:00
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
@@ -6,6 +6,7 @@ public class AsyncCatcher
{
public static boolean enabled = true;
+ public static boolean shuttingDown = false; // Paper
public static void catchOp(String reason)
{
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
2021-03-16 07:19:45 +00:00
index d76e01d73da7413f192132134caf201d7780e3f1..a45155cdd7d7a302c119f75bfe2b428ae5e8ab47 100644
2018-02-15 05:34:58 +00:00
--- a/src/main/java/org/spigotmc/RestartCommand.java
+++ b/src/main/java/org/spigotmc/RestartCommand.java
@@ -43,6 +43,7 @@ public class RestartCommand extends Command
2019-01-01 03:15:55 +00:00
private static void restart(final String restartScript)
2018-02-15 05:34:58 +00:00
{
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
try
{
2019-01-01 03:15:55 +00:00
String[] split = restartScript.split( " " );