undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
162
defects/minecraft/PistonStructureResolver.java
Normal file
162
defects/minecraft/PistonStructureResolver.java
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
package net.minecraft.world.level.block.piston;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
|
||||
// FIX minecraft-0002: parallel HashSet<BlockPos> for O(1) duplicate detection in toPush
|
||||
public class PistonStructureResolver {
|
||||
public static final int MAX_PUSH_DEPTH = 12;
|
||||
private final Level level;
|
||||
private final BlockPos pistonPos;
|
||||
private final boolean extending;
|
||||
private final BlockPos startPos;
|
||||
private final Direction pushDirection;
|
||||
private final List<BlockPos> toPush = Lists.newArrayList();
|
||||
private final Set<BlockPos> toPushSet = new HashSet<>(); // FIX: parallel set
|
||||
private final List<BlockPos> toDestroy = Lists.newArrayList();
|
||||
private final Direction pistonDirection;
|
||||
|
||||
public PistonStructureResolver(Level level, BlockPos pistonPos, Direction direction, boolean extending) {
|
||||
this.level = level;
|
||||
this.pistonPos = pistonPos;
|
||||
this.pistonDirection = direction;
|
||||
this.extending = extending;
|
||||
if (extending) {
|
||||
this.pushDirection = direction;
|
||||
this.startPos = pistonPos.relative(direction);
|
||||
} else {
|
||||
this.pushDirection = direction.getOpposite();
|
||||
this.startPos = pistonPos.relative(direction, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean resolve() {
|
||||
this.toPush.clear();
|
||||
this.toPushSet.clear(); // FIX
|
||||
this.toDestroy.clear();
|
||||
BlockState nextState = this.level.getBlockState(this.startPos);
|
||||
if (!PistonBaseBlock.isPushable(nextState, this.level, this.startPos, this.pushDirection, false, this.pistonDirection)) {
|
||||
if (this.extending && nextState.getPistonPushReaction() == PushReaction.DESTROY) {
|
||||
this.toDestroy.add(this.startPos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!this.addBlockLine(this.startPos, this.pushDirection)) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < this.toPush.size(); ++i) {
|
||||
BlockPos pos = this.toPush.get(i);
|
||||
if (!PistonStructureResolver.isSticky(this.level.getBlockState(pos)) || this.addBranchingBlocks(pos)) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isSticky(BlockState state) {
|
||||
return state.is(Blocks.SLIME_BLOCK) || state.is(Blocks.HONEY_BLOCK);
|
||||
}
|
||||
|
||||
private static boolean canStickToEachOther(BlockState state1, BlockState state2) {
|
||||
if (state1.is(Blocks.HONEY_BLOCK) && state2.is(Blocks.SLIME_BLOCK)) return false;
|
||||
if (state1.is(Blocks.SLIME_BLOCK) && state2.is(Blocks.HONEY_BLOCK)) return false;
|
||||
return PistonStructureResolver.isSticky(state1) || PistonStructureResolver.isSticky(state2);
|
||||
}
|
||||
|
||||
private boolean addBlockLine(BlockPos start, Direction direction) {
|
||||
int i;
|
||||
BlockState nextState = this.level.getBlockState(start);
|
||||
if (nextState.isAir()) return true;
|
||||
if (!PistonBaseBlock.isPushable(nextState, this.level, start, this.pushDirection, false, direction)) return true;
|
||||
if (start.equals(this.pistonPos)) return true;
|
||||
if (this.toPushSet.contains(start)) return true; // FIX: O(1) instead of O(N)
|
||||
int blockCount = 1;
|
||||
if (blockCount + this.toPush.size() > 12) return false;
|
||||
while (PistonStructureResolver.isSticky(nextState)) {
|
||||
BlockPos pos = start.relative(this.pushDirection.getOpposite(), blockCount);
|
||||
BlockState previousState = nextState;
|
||||
nextState = this.level.getBlockState(pos);
|
||||
if (nextState.isAir() || !PistonStructureResolver.canStickToEachOther(previousState, nextState)
|
||||
|| !PistonBaseBlock.isPushable(nextState, this.level, pos, this.pushDirection, false, this.pushDirection.getOpposite())
|
||||
|| pos.equals(this.pistonPos)) break;
|
||||
if (++blockCount + this.toPush.size() <= 12) continue;
|
||||
return false;
|
||||
}
|
||||
int blocksAdded = 0;
|
||||
for (i = blockCount - 1; i >= 0; --i) {
|
||||
BlockPos p = start.relative(this.pushDirection.getOpposite(), i);
|
||||
this.toPush.add(p);
|
||||
this.toPushSet.add(p); // FIX
|
||||
++blocksAdded;
|
||||
}
|
||||
i = 1;
|
||||
while (true) {
|
||||
BlockPos pos;
|
||||
int collisionPos;
|
||||
if ((collisionPos = this.toPush.indexOf(pos = start.relative(this.pushDirection, i))) > -1) {
|
||||
this.reorderListAtCollision(blocksAdded, collisionPos);
|
||||
for (int j = 0; j <= collisionPos + blocksAdded; ++j) {
|
||||
BlockPos blockPos = this.toPush.get(j);
|
||||
if (!PistonStructureResolver.isSticky(this.level.getBlockState(blockPos)) || this.addBranchingBlocks(blockPos)) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
nextState = this.level.getBlockState(pos);
|
||||
if (nextState.isAir()) return true;
|
||||
if (!PistonBaseBlock.isPushable(nextState, this.level, pos, this.pushDirection, true, this.pushDirection) || pos.equals(this.pistonPos)) return false;
|
||||
if (nextState.getPistonPushReaction() == PushReaction.DESTROY) {
|
||||
this.toDestroy.add(pos);
|
||||
return true;
|
||||
}
|
||||
if (this.toPush.size() >= 12) return false;
|
||||
this.toPush.add(pos);
|
||||
this.toPushSet.add(pos); // FIX
|
||||
++blocksAdded;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
private void reorderListAtCollision(int blocksAdded, int collisionPos) {
|
||||
ArrayList<BlockPos> head = Lists.newArrayList();
|
||||
ArrayList<BlockPos> lastLineAdded = Lists.newArrayList();
|
||||
ArrayList<BlockPos> collisionToLine = Lists.newArrayList();
|
||||
head.addAll(this.toPush.subList(0, collisionPos));
|
||||
lastLineAdded.addAll(this.toPush.subList(this.toPush.size() - blocksAdded, this.toPush.size()));
|
||||
collisionToLine.addAll(this.toPush.subList(collisionPos, this.toPush.size() - blocksAdded));
|
||||
this.toPush.clear();
|
||||
this.toPush.addAll(head);
|
||||
this.toPush.addAll(lastLineAdded);
|
||||
this.toPush.addAll(collisionToLine);
|
||||
// toPushSet is derived from toPush; rebuild it
|
||||
this.toPushSet.clear();
|
||||
this.toPushSet.addAll(this.toPush);
|
||||
}
|
||||
|
||||
private boolean addBranchingBlocks(BlockPos fromPos) {
|
||||
BlockState fromState = this.level.getBlockState(fromPos);
|
||||
for (Direction direction : Direction.values()) {
|
||||
BlockPos neighbourPos;
|
||||
BlockState neighbourState;
|
||||
if (direction.getAxis() == this.pushDirection.getAxis()
|
||||
|| !PistonStructureResolver.canStickToEachOther(neighbourState = this.level.getBlockState(neighbourPos = fromPos.relative(direction)), fromState)
|
||||
|| this.addBlockLine(neighbourPos, direction)) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Direction getPushDirection() { return this.pushDirection; }
|
||||
public List<BlockPos> getToPush() { return this.toPush; }
|
||||
public List<BlockPos> getToDestroy() { return this.toDestroy; }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue