From fa87f628918e476072d223307558f9f3130483f3 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 8 Aug 2023 17:29:33 -0700
Subject: [PATCH] Fix race condition on UpgradeData.BlockFixers class init

The CHUNKY_FIXERS field is modified during the constructors
of the BlockFixers, but the code that uses CHUNKY_FIXERS does
not properly ensure that BlockFixers has been initialised before
using it, leading to a possible race condition where instances of
BlockFixers are accessed before they have initialised correctly.

We can force the class to initialise fully before accessing the
field by calling any method on the class, and for convenience
we use values().
---
 .../world/level/chunk/UpgradeData.java.patch  | 36 ++++++++++---------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch
index a822d43229..902ea36be8 100644
--- a/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch
@@ -1,13 +1,9 @@
 --- a/net/minecraft/world/level/chunk/UpgradeData.java
 +++ b/net/minecraft/world/level/chunk/UpgradeData.java
-@@ -109,9 +109,28 @@
-         if (nbt.contains(key, 9)) {
-             for (Tag tag : nbt.getList(key, 10)) {
-                 SavedTick.loadTick((CompoundTag)tag, nameToType).ifPresent(ticks::add);
-+            }
-+        }
-+    }
-+
+@@ -113,12 +113,36 @@
+         }
+     }
+ 
 +    // Paper start - filter out relocated neighbour ticks
 +    // The lists are only supposed to contain ticks for the 1 radius neighbours of the chunk
 +    private static <T> void filterTickList(int chunkX, int chunkZ, List<SavedTick<T>> ticks) {
@@ -22,22 +18,30 @@
 +            if (dist != 1) {
 +                LOGGER.warn("Neighbour tick '" + tick + "' serialized in chunk (" + chunkX + "," + chunkZ + ") is too far (" + tickCX + "," + tickCZ + ")");
 +                iterator.remove();
-             }
-         }
-     }
++            }
++        }
++    }
 +    // Paper end - filter out relocated neighbour ticks
- 
++
      public void upgrade(LevelChunk chunk) {
          this.upgradeInside(chunk);
-@@ -120,6 +139,11 @@
+ 
+         for (Direction8 direction8 : DIRECTIONS) {
              upgradeSides(chunk, direction8);
          }
- 
++
 +        // Paper start - filter out relocated neighbour ticks
 +        filterTickList(chunk.locX, chunk.locZ, this.neighborBlockTicks);
 +        filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks);
 +        // Paper end - filter out relocated neighbour ticks
-+
+ 
          Level level = chunk.getLevel();
          this.neighborBlockTicks.forEach(tick -> {
-             Block block = tick.type() == Blocks.AIR ? level.getBlockState(tick.pos()).getBlock() : tick.type();
+@@ -129,6 +153,7 @@
+             Fluid fluid = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type();
+             level.scheduleTick(tick.pos(), fluid, tick.delay(), tick.priority());
+         });
++        UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised
+         CHUNKY_FIXERS.forEach(logic -> logic.processChunk(level));
+     }
+