aboutsummaryrefslogtreecommitdiffhomepage
path: root/Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch
diff options
context:
space:
mode:
Diffstat (limited to 'Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch')
-rw-r--r--Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch86
1 files changed, 86 insertions, 0 deletions
diff --git a/Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch b/Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch
new file mode 100644
index 0000000000..457aa012d7
--- /dev/null
+++ b/Spigot-Server-Patches/0051-Ensure-commands-are-not-ran-async.patch
@@ -0,0 +1,86 @@
+From d94378d518cda98be6fc17c01200ed86b7ac3790 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Thu, 3 Mar 2016 01:17:12 -0600
+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.
+
+diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
+index e19513a96..fd2c0c4f2 100644
+--- a/src/main/java/net/minecraft/server/PlayerConnection.java
++++ b/src/main/java/net/minecraft/server/PlayerConnection.java
+@@ -1267,6 +1267,29 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
+ }
+
+ if (!async && s.startsWith("/")) {
++ // Paper Start
++ if (org.spigotmc.AsyncCatcher.enabled && !org.bukkit.Bukkit.isPrimaryThread()) {
++ 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());
++ }
++ }
++ // Paper End
+ this.handleCommand(s);
+ } else if (this.player.getChatFlags() == EntityHuman.EnumChatVisibility.SYSTEM) {
+ // 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
+index 30ed3ad58..a795a165a 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+@@ -647,6 +647,29 @@ public final class CraftServer implements Server {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(commandLine, "CommandLine cannot be null");
+
++ // Paper Start
++ if (org.spigotmc.AsyncCatcher.enabled && !Bukkit.isPrimaryThread()) {
++ 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());
++ }
++ }
++ // Paper End
++
+ if (commandMap.dispatch(sender, commandLine)) {
+ return true;
+ }
+--
+2.12.0.windows.1
+