Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Folia: Cause.Builder reads Creature#getTarget() from a non-owning region during vehicle damage

未关闭
#2,311 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
72/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
java
领域
api, backend

调研方向

Start in Cause.java at Cause.Builder.addAll(...), then trace the call from EventAbstractionListener.onVehicleDamage. Use the deterministic event harness described in the report to reproduce the cross-region access. Done means cause construction preserves the projectile and shooter, avoids remote mutable-state reads, and lets the vehicle protection check complete normally.

由索引模型根据 Issue 内容生成。

描述

WorldEdit Version

WorldEdit 7.4.3+7515-78babeb

WorldGuard Version

WorldGuard 7.0.17+2370-e42d8bc

Platform Version

  • Official Folia 1.21.11-14-ver/1.21.11@529aabc
  • Minecraft 1.21.11
  • Java 25.0.3
  • Four Folia region tick threads

The Folia server JAR was downloaded from PaperMC's official download service.

Confirmations

  • I am using the most recent Minecraft release.
  • I am using a version of WorldEdit compatible with my Minecraft version.
  • I am using a version of WorldGuard compatible with my Minecraft version.
  • I am using the latest or recommended version of my platform software.
  • I am NOT using a hybrid server, e.g. a server that combines Bukkit and Forge.
  • I am NOT using a fork of WorldEdit, such as FastAsyncWorldEdit or AsyncWorldEdit.

Bug Description

When a projectile has a Creature shooter owned by a different Folia region, WorldGuard reads the shooter's mutable AI state from the projectile or vehicle region thread while building the event cause chain.

The problem is in Cause.Builder.addAll(...). After following Projectile#getShooter(), WorldGuard reaches the remote Creature and unconditionally calls Creature#getTarget(). Folia correctly rejects this read because the current region does not own the creature.

This was reproduced on an isolated official Folia server. Immediately before firing VehicleDamageEvent, the ownership checks returned:

Bukkit.isOwnedByCurrentRegion(arrow)    = true
Bukkit.isOwnedByCurrentRegion(pillager) = false

WorldGuard then produced this call path:

Thread failed main thread check: Accessing entity state off owning region's thread
at ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(TickThread.java:97)
at org.bukkit.craftbukkit.entity.CraftPillager.getHandle(CraftPillager.java:16)
at org.bukkit.craftbukkit.entity.CraftMob.getTarget(CraftMob.java:71)
at com.sk89q.worldguard.bukkit.cause.Cause$Builder.addAll(Cause.java:336)
at com.sk89q.worldguard.bukkit.cause.Cause$Builder.addAll(Cause.java:298)
at com.sk89q.worldguard.bukkit.cause.Cause.create(Cause.java:226)
at com.sk89q.worldguard.bukkit.listener.EventAbstractionListener.onVehicleDamage(EventAbstractionListener.java:1005)

The exception aborts the WorldGuard listener before it completes its protection check. The VehicleDamageEvent returns without being cancelled, so a protected vehicle may remain vulnerable.

Expected Behavior

WorldGuard should keep the projectile and its shooter in the cause chain without reading mutable state from an entity owned by another Folia region.

If the current region owns the creature, WorldGuard may continue resolving getTarget() and getIgniter(). If it does not own the creature, WorldGuard should skip only that recursive AI-state expansion and continue processing the event normally.

Reproduction Steps

  1. Start official Folia 1.21.11-14 (529aabc) with four region tick threads and Java 25.
  2. Install WorldEdit 7.4.3+7515-78babeb and WorldGuard 7.0.17+2370-e42d8bc.
  3. In region A near x=0, create a persistent pillager.
  4. Create an arrow in region A and assign the pillager as its shooter.
  5. Move the arrow to region B near x=16384 with teleportAsync(...), leaving the pillager in region A.
  6. On the arrow's entity scheduler in region B, create a minecart and fire a real Bukkit VehicleDamageEvent with the arrow as the attacker.
  7. Confirm that Bukkit.isOwnedByCurrentRegion(arrow) is true and Bukkit.isOwnedByCurrentRegion(pillager) is false on the event thread.
  8. Observe WorldGuard calling CraftMob#getTarget() through Cause.Builder.addAll(...) and Folia rejecting the cross-region entity-state read.

The test uses a deterministic event harness to isolate WorldGuard's listener. It does not modify WorldGuard or Folia internals.

Optional WorldGuard-Report

Not applicable. This failure occurs while WorldGuard constructs the event cause, before a region-specific protection result can be completed.

Anything Else?

The relevant WorldGuard logic currently reads creature state recursively without checking Folia ownership:

} else if (o instanceof Creeper creeper) {
    indirect = true;
    addAll(creeper.getTarget(), creeper.getIgniter());
} else if (o instanceof Creature creature) {
    indirect = true;
    addAll(creature.getTarget());
}

A possible fix is to preserve the creature as a cause but guard only the mutable target and igniter lookups:

} else if (o instanceof Creeper creeper) {
    indirect = true;
    if (!WorldGuardPlugin.inst().isFolia()
            || Bukkit.isOwnedByCurrentRegion(creeper)) {
        addAll(creeper.getTarget(), creeper.getIgniter());
    }
} else if (o instanceof Creature creature) {
    indirect = true;
    if (!WorldGuardPlugin.inst().isFolia()
            || Bukkit.isOwnedByCurrentRegion(creature)) {
        addAll(creature.getTarget());
    }
}

Bukkit.isOwnedByCurrentRegion(Entity) is suitable here because it checks ownership without first reading the remote entity's location or other owner-only state.

Moving cause construction to the shooter's scheduler is not a safe replacement: vehicle-event cancellation must finish synchronously on the vehicle's owning region, and blocking one region while waiting for another can introduce deadlocks or tick latency.

主要语言
Java
星标
939
派生
672
平均合并
22 小时 57 分钟
30 天内合并 PR
1

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

EngineHub/WorldGuard 的其他 Issue

查看 EngineHub/WorldGuard 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。