java-topology/tools/tickets/defects/minecraft-0002.md
russell@unturf.com db29a08762 undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections.
Squash of 94 local commits onto remote master.
2026-03-26 19:48:18 -04:00

2.4 KiB
Raw Permalink Blame History

id repo file line status severity complexity pattern source created
minecraft-0002 Mojang/minecraft-java-edition net/minecraft/world/level/block/piston/PistonStructureResolver.java (decompiled) addBlockLine / resolve methods unpatched LOW O(P²) — P = piston push chain length, hardcoded max 12 List<BlockPos>.contains() in piston chain resolution loop decompiled from ~/Downloads/server.jar (server-26.1) 2026-03-24

Defect

File: net/minecraft/world/level/block/piston/PistonStructureResolver (decompiled) Pattern: this.toPush.contains(start)toPush is List<BlockPos> Trigger: Every piston activation

Description

PistonStructureResolver resolves which blocks a piston pushes or destroys. It maintains toPush as an ArrayList<BlockPos>. When adding a block to the push chain, it checks for duplicates with a list scan:

if (this.toPush.contains(start)) {
    return true;
}

BlockPos equality is value-based (x,y,z integers). List.contains is a linear scan.

Severity constraint

Minecraft hardcodes a maximum of 12 pushed blocks per piston activation:

if (blockCount + this.toPush.size() > 12) {
    return false;
}

The maximum list size is 12. O(P²) with P≤12 = at most 144 comparisons per piston activation. Not catastrophic. Principle violation, not a performance crisis.

However: redstone contraptions with many pistons firing simultaneously multiply this. A 16×16 piston array firing synchronously = 256 pistons × 144 comparisons = 36,864 comparisons per game tick. At 20 TPS, that is 737,280 comparisons/second from list scans alone.

Fix

Replace List<BlockPos> with parallel Set<BlockPos> for O(1) duplicate check:

// Before
private final List<BlockPos> toPush = Lists.newArrayList();

// After
private final List<BlockPos> toPush = Lists.newArrayList();
private final Set<BlockPos> toPushSet = new HashSet<>();

// Contains check:
if (this.toPushSet.contains(start)) { return true; }

// Add:
this.toPush.add(pos); this.toPushSet.add(pos);

toPushSet is used only for O(1) duplicate detection; toPush preserves order for the push sequence. Same pattern as javac-0001 (Tarjan stack → parallel set).

Work items

  • Confirm with decompiler (CFR/Procyon) that contains is called on the list
  • Report to Mojang bug tracker
  • Note: bounded at 12, so LOW priority — but correct the principle violation