Skip to content

Bundled FART 1.0.14 has a race condition producing randomly broken transformation output (unmapped names -> AbstractMethodError); the FART fork repo is archived so this is filed here #2295

Description

@yu1745

Why this is filed here: This bug belongs to org.sinytra:ForgeAutoRenamingTool (the FART fork bundled in Connector), but that repository is archived (no PRs/issues accepted), so there is no place to report it upstream other than here. Please forward or re-file as appropriate.

Versions:

  • Connector: 1.0.0-beta.49+1.20.1 (bundles FART 1.0.14)
  • FART fork: Sinytra/ForgeAutoRenamingTool @ 99817d8 (archived)
  • Forge: 1.20.1-47.4.x, Minecraft 1.20.1

Describe the bug:

Jar transformation output is non-deterministic. For the same input jar and the same Connector version, repeated fresh transformations sometimes produce correct output and sometimes broken output, where a lambda call site is left with its Yarn name unmapped (InvokeDynamic #0:getColor:()Lnet/minecraft/client/color/block/BlockColor; instead of m_92566_), while the descriptor and bootstrap args are correctly remapped. At runtime LambdaMetafactory then generates a class implementing getColor(...) while the interface method resolves to m_92566_(...) → random client crashes:

java.lang.AbstractMethodError: Receiver class ic2_120.client.colorprovider.StorageBoxColorProvider$$Lambda$5456/0x... does not define or
inherit an implementation of the resolved method 'abstract int m_92566_(BlockState, BlockAndTintGetter, BlockPos, int)' of interface
net.minecraft.client.color.block.BlockColor.

This is not specific to IC2 or color interfaces: the race lives in the shared MClass cache of FART 1.0.14 (commit 99817d8 publishes half-built MClass instances into resolved mid-construction). Any Fabric mod whose lambdas implement MC interfaces, or whose classes rely on inherited-member mapping, can be affected.

Steps to reproduce:

  1. Minimal set: Connector beta.49 + FFAPI + a Fabric mod registering a BlockColor/ItemColor lambda (e.g. IC2 Refabricate 0.5 + fabric-language-kotlin).
  2. Delete mods/.connector, start the server, wait for transformation, inspect the output jar with javap (call-site name getColor = broken, m_92566_ = good).
  3. Repeat: the result flips randomly (measured: 1 broken output in 8 samples; with the fix: 0 broken in 88 samples).
  4. Enter a world containing the affected block → chunk rendering calls the interface method → AbstractMethodError.

Root cause (FART 1.0.14, EnhancedRemapper):

  • MClass constructor executes resolved.put(cls, Optional.of(this)) before filling fields/methods maps (introduced by 99817d8 to break circular parent dependencies, fixing Failed to remap ReplayMod with StackOverflowError #1592-style StackOverflow);
  • getClass has a lock-free fast path that can observe the half-built instance from another worker thread (FART processes classes with a work-stealing pool; Connector transforms multiple jars in parallel on a shared remapper);
  • getMethod/getField cache negative lookups (computeIfAbsent(k -> Optional.empty())), so the observing thread permanently caches empty results, or a subclass pulls down empty inherited members — unmapped names end up in the output jar.

A plain revert would re-introduce the circular-dependency StackOverflow, so both constraints need to hold (no half-built visibility + cycle short-circuit). A working fix addressing both, with adversarial unit tests and end-to-end verification (88 fresh transformations, 0 broken), is available here for reference: yu1745/ForgeAutoRenamingTool@553b453

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions