mojira.dev
MC-310635

`/item override` and `/item fill` with a `contents` slot source targeting the `charged_projectiles` component freezes the server for several seconds

/item override (and /item fill) targeting the charged_projectiles component through a "contents"
slot source makes the server thread spin 2,147,483,647 times inside
SimpleMutableContainer#insertNewSlots before it returns. The command then completes normally, with
no error and nothing in the log — the only symptom is that the server is completely frozen for
several seconds. Measured 0.5 to 8.8 seconds depending on the variant and JIT state; a clean
measurement on my machine was 2,555 ms for /item override.

A repeating command block re-triggers this every tick, which makes the freeze permanent.

Steps to Reproduce

  1. Create a world with cheats on.

  2. Hold any item. The charged_projectiles component does not need to be present already, because
    the code path uses getOrDefault.

  3. Run:
    /item override entity @s {type:"contents",component:"charged_projectiles",slot_source:{type:"slot_range",slots:"weapon.mainhand"}} with arrow

  4. The command reports success. The server is unresponsive for several seconds first.

A second trigger, through the /item fill provider, with container.0 empty:
/item fill entity @s {type:"contents",component:"charged_projectiles",slot_source:{type:"slot_range",slots:"weapon.mainhand"}} from entity @s container.0

/item replace is not affected — it terminates after a single iteration.

Expected Results

The insertion loop stops as soon as an insertion fails, so the command returns immediately.

Cause

SimpleMutableContainer#insertNewSlots (world/item/component/SimpleMutableContainer.java:61-72):

protected int insertNewSlots(final ItemProvider newItems, final SlotSelector slotSelector) {
int successCount = 0;

 while (newItems.hasNext() && this.canInsertNewSlots() && slotSelector.trySelectSlot(ItemStack.EMPTY)) {
    boolean success = this.addSlotWithItem(newItems.next());
    if (success) {
       successCount++;
    }
 }

 return successCount;

}

There is no break when an insertion fails, and for charged_projectiles all three loop conditions
are permanently true:

  • newItems.hasNext(): /item override builds
    ItemProvider.of(items).orElseProvide(ItemStack.EMPTY) (ItemCommands.java:189), and
    FallbackItemProvider#hasNext is a literal "return true" (ItemProvider.java:53-55). /item fill
    builds ItemProvider.cycle(items) (ItemCommands.java:185), whose hasNext is also permanently
    true when the source is non-empty.

  • this.canInsertNewSlots(): ChargedProjectiles.Mutable#canInsertNewSlots is items.size() < 1024,
    and items never grows, because ChargedProjectiles.Mutable#addSlotWithItem is
    "return !itemStack.isEmpty() && super.addSlotWithItem(itemStack);" — it rejects the empty
    fallback stack without adding a slot.

  • slotSelector.trySelectSlot(...): SlotSelector.tracking hardcodes Integer.MAX_VALUE as its limit
    (SlotSelector.java:23-25).

So the loop runs until the selector's counter saturates at 2^31-1.

Why this is a bug and not a design choice

There are exactly three ContainerComponent.Mutable implementations, and one of them already has
the missing guard. BundleContents.Mutable overrides insertNewSlots for precisely this reason
(world/item/component/BundleContents.java:298-311):

boolean success = newItems.findNextNonEmpty() && this.addSlotWithItem(newItems.peek());
if (!success) {
break;
}

ItemContainerContents.Mutable does not need the guard because its slot count does grow, so
size < 256 terminates it. ChargedProjectiles.Mutable is the only one that can fail an insertion
without growing, and it is the only one that inherits the break-less base loop.

Measured, all three driven with the same provider the /item override path builds:

ChargedProjectiles replaced=1 iterations=2147483647 2555 ms
ItemContainerContents replaced=256 iterations=256 0 ms
BundleContents replaced=1 iterations=2 0 ms

Related

MC-310315 ("number providers that reference themselves crash the game", Resolved/Fixed in
26.3 Snapshot 6) shows Mojang treats non-termination in this subsystem as a defect and fixed a
different instance of it in this very build.

Comments 0

No comments.

yuluo

FiskFille

Confirmed

Platform HC

Very Important

Data Packs

26.3 Snapshot 6

26.3 Snapshot 10

Retrieved