Type of bug
Error in console
/ess dump all output
https://essentialsx.net/dump?bytebin=SoVSMwf325
Error log (if applicable)
https://pastes.dev/mRentNB1AY
Bug description
When a player joins the server, Essentials throws an IndexOutOfBoundsExceptin in AsyncPlaerSendCommandsEvent.
Steps to reproduce
- enable Essentials
- join the server
Expected behaviour
Essentials doesn't throw an exception
Actual behaviour
Essentials throws an exception
Additional Information
Versions: reproduced on EssentialsX 2.22.0 and 2.22.1-dev+17-382de4f, Paper 26.2 and 1.21.11
One stack trace per player join, via AsyncPlayerSendCommandsEvent:
[14:15:22 ERROR]: Could not pass event AsyncPlayerSendCommandsEvent to Essentials v2.22.1-dev+17-382de4f
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100) ~[?:?]
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106) ~[?:?]
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302) ~[?:?]
at java.base/java.util.Objects.checkIndex(Objects.java:365) ~[?:?]
at java.base/java.util.ArrayList.get(ArrayList.java:428) ~[?:?]
at EssentialsX.jar//com.earth2me.essentials.AlternativeCommandsHandler.getAlternative(AlternativeCommandsHandler.java:133) ~[?:?]
at EssentialsX.jar//com.earth2me.essentials.EssentialsPlayerListener$CommandSendFilter.isEssentialsCommand(EssentialsPlayerListener.java:1279) ~[?:?]
at EssentialsX.jar//com.earth2me.essentials.EssentialsPlayerListener$CommandSendFilter.lambda$apply$0(EssentialsPlayerListener.java:1254) ~[?:?]
at EssentialsX.jar//net.ess3.provider.providers.PaperCommandSendListenerProvider.lambda$onAsyncCommandSend$0(PaperCommandSendListenerProvider.java:28) ~[?:?]
at java.base/java.util.Collection.removeIf(Collection.java:581) ~[?:?]
at EssentialsX.jar//net.ess3.provider.providers.PaperCommandSendListenerProvider.onAsyncCommandSend(PaperCommandSendListenerProvider.java:28) ~[?:?]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:71) ~[paper-api-26.2.build.112-stable.jar:?]
at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:54) ~[paper-26.2.jar:26.2-112-c9e894d]
at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:131) ~[paper-26.2.jar:26.2-112-c9e894d]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:627) ~[paper-api-26.2.build.112-stable.jar:?]
at org.bukkit.event.Event.callEvent(Event.java:46) ~[paper-api-26.2.build.112-stable.jar:?]
at net.minecraft.commands.Commands.sendAsync(Commands.java:517) ~[paper-26.2.jar:26.2-112-c9e894d]
at net.minecraft.commands.Commands.lambda$sendCommands$0(Commands.java:491) ~[paper-26.2.jar:26.2-112-c9e894d]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090) ~[?:?]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614) ~[?:?]
at java.base/java.lang.Thread.run(Thread.java:1474) ~[?:?]
Potential cause: getAlternative guards for an empty list on entry, then prunes dead WeakReferences inside the loop, then reads element 0 without re-checking:
if (commands == null || commands.isEmpty()) return null; // passes: entries exist
if (commands.size() == 1) return commands.get(0).get();
for (Iterator<WeakReference<Command>> it = commands.iterator(); it.hasNext();) {
Command cmd = it.next().get();
if (cmd == null) { it.remove(); continue; } // may empty the list
if (cmd.getName().equalsIgnoreCase(label)) return cmd;
}
return commands.get(0).get(); // line 133 — throws when emptied
If every entry in a bucket is a collected reference, the loop empties the list and get(0) throws. The WeakReferences came in with #5539.
Alternatively, this could also be a concurrency issue. According to the stack trace, commands is a regular ArrayList that gets read and modified non-atomically in an async event.
Impact: caught per-event, so the join completes. What's lost is Essentials filtering its own aliases out of the command list sent to the client, i.e. tab completion for that player.
Type of bug
Error in console
/ess dump alloutputhttps://essentialsx.net/dump?bytebin=SoVSMwf325
Error log (if applicable)
https://pastes.dev/mRentNB1AY
Bug description
When a player joins the server, Essentials throws an IndexOutOfBoundsExceptin in AsyncPlaerSendCommandsEvent.
Steps to reproduce
Expected behaviour
Essentials doesn't throw an exception
Actual behaviour
Essentials throws an exception
Additional Information
Versions: reproduced on EssentialsX
2.22.0and2.22.1-dev+17-382de4f, Paper26.2and1.21.11One stack trace per player join, via
AsyncPlayerSendCommandsEvent:Potential cause:
getAlternativeguards for an empty list on entry, then prunes deadWeakReferences inside the loop, then reads element 0 without re-checking:If every entry in a bucket is a collected reference, the loop empties the list and
get(0)throws. TheWeakReferences came in with #5539.Alternatively, this could also be a concurrency issue. According to the stack trace,
commandsis a regularArrayListthat gets read and modified non-atomically in an async event.Impact: caught per-event, so the join completes. What's lost is Essentials filtering its own aliases out of the command list sent to the client, i.e. tab completion for that player.