Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixin local variable analysis misbehaving #768

Closed
Su5eD opened this issue Apr 2, 2024 · 0 comments · Fixed by #945
Closed

Mixin local variable analysis misbehaving #768

Su5eD opened this issue Apr 2, 2024 · 0 comments · Fixed by #945
Labels
triage Needs triaging and confirmation

Comments

@Su5eD
Copy link
Contributor

Su5eD commented Apr 2, 2024

Minecraft Version: 1.20.4

NeoForge Version: 20.4.218

Logs: https://mclo.gs/1JbVF64


A strange encounter

To give this a little background: It all started with a bug report I've received in Connector about a certain mod's mixin not applying. Specifically, it could not locate an implicit variable in its target method. After investigating the crash, I was left confused as the predicted local variables that should've been available at one of the mixin's injection points did not match mixin's analysis results. To make matters more curious, the target method wasn't modified by NeoForge at all. This led me to compare the results on both NeoForge and Fabric in an attempt to figure out what was wrong, with a surprising outcome.

I've verified this bug by implementing the same mixin on both NeoForge and Fabric to make sure this wasn't a side effect of Connector, but I figured I'd still mention it to explain how I came to compare Neo and Fabric Mixin behavior in the first place.

All of this comes down to a single method in Mixin, which is responsible for "guessing" the available local variables at a given injection point - Locals#getLocalsAt.
Let's take a closer look - below is my Mixin class I've used to reproduce this bug on NeoForged using (Fabric) Mixin version 0.13.0+mixin.0.8.5, although it's worth mentioning this applies to upstream Mixin as well.

@Mixin(LiquidBlock.class)  
public class LiquidBlockMixin {  

    @ModifyReturnValue(method = "shouldSpreadLiquid", at = @At("RETURN"))  
    private boolean thisMixinWontWorkNoMatterWhat(boolean original, @Local Level world, @Local BlockPos pos) {  
        return original;  
    }  
}

Get the complete minimal reproduction examples here:

Expected behavior

Below you can find an overview of our target method, net.minecraft.world.level.block.LiquidBlock#shouldSpreadLiquid.
There are 3 total return instructions, which gives 3 candidate injection points. To pass, the mixin must successfully inject into at least one of them. We are implicitly capturing a BlockPos and BlockState local variable. (The requirement for capturing implicit local variables being that there must only be one variable of the given type present at the injection point).

From the image below, we can observe that only one injection point out of three satisfies this requirement. The other two will fail to inject and remain ignored. Let's focus on the third return statement, which is our desired injection target for this reproduction case.

Target overview

Actual behavior

At first glance, everything appears to be correct. When trying to launch the game, however, we are met with an unexpected crash. This happens due to all of the 3 possible injection points being rejected.

Suppressed: com.llamalad7.mixinextras.sugar.impl.SugarApplicationException: Failed to validate sugar @Local BlockPos on method
Caused by: org.spongepowered.asm.mixin.injection.modify.InvalidImplicitDiscriminatorException: Found 2 candidate variables but exactly 1 is required.

What does Mixin have to say about locals at our injection point? I called the responsible method using the IDE debug evaluator to find several "ghost" variables present at the injection point, which shouldn't've existed. On Fabric, Mixin reported only 4 variables present - the class instance and 3 method arguments.

Show evaluation result

Curiously, despite the method in question being the same on both platforms, the mixin applies perfectly fine on Fabric, but breaks on Neo. Still, there was a chance Neo's recompilation of the class modified some of the variables' scopes or frames. To eliminate this possibility, I called the getLocalsAt method on the same instruction in a clean srg minecraft class, with the results being identical. At that point, I had eliminated any possibility this was caused by a difference in code.

Troublesome flags

I suspected this had something to do with how the method's frames are layed out, and after a while of poking around I've found out that the results are affected by whether the EXPAND_FRAMES flag is used when reading the ClassNode. And so, I went on to investigate the origin of ClassNodes used in the process.

Let's take a brief look at the contents of getLocalsAt:

public static LocalVariableNode[] getLocalsAt(ClassNode classNode, MethodNode method, AbstractInsnNode node, Settings settings) {  
//  ...
    ClassInfo classInfo = ClassInfo.forName(classNode.name);
// ...

There's a ClassNode classNode we're passing in as the input and a ClassInfo classInfo object, which holds pre-computed information about the class represented by classNode. The former is created by modlauncher in ClassTransformer#transform using 0 as the reader flags, while the ClassInfo is constructed using a ClassNode returned by mixins's byte code provider. In modlauncher, this happends to be MixinLaunchPluginLegacy#getClassNode, which uses ClassReader.EXPAND_FRAMES to read the class.

As it turns out, Fabric does the exact opposite:

  • ClassNodes intended for transformation by mixin are parsed using ClassReader.EXPAND_FRAMES
  • Classes returned by the bytecode provider use no flags

After testing with locally modified builds of modlauncher and mixin with the reader flags now set to match Fabric, the mixin injector applied just as expected.

Solutions

I'm not familiar with the inner workings of the getLocalsAt function, and looking at it's code, I'm not sure I want to be. However, I can make some conclusions based on my observations of its behavior:

  • (our current setup) Using 0 for the input ClassNode and EXPAND_FRAMES for the ClassInfo node will produce inaccurate results with variables that are out of scope at the input instruction node.
  • Using 0 for the input and 0 for ClassInfo can lead to unexpected ArrayIndexOutOfBoundsExceptions in some cases
  • (our optimal choice) Using EXPAND_FRAMES for the input and 0 for ClassInfo node produces expected results

My proposal here is to update our bytecode provider and modlauncher's class reader to use the same flags as Fabric does for their ClassNodes. This might be a potentially breaking change and will require further testing to determine its impact on mods, but all things considered, if it works on Fabric, there's no reason it wouldn't for for us, too.

@Su5eD Su5eD added the triage Needs triaging and confirmation label Apr 2, 2024
Su5eD added a commit to Su5eD/FabricMixin that referenced this issue Apr 15, 2024
Su5eD added a commit to Su5eD/modlauncher that referenced this issue Apr 16, 2024
marchermans pushed a commit to McModLauncher/modlauncher that referenced this issue Apr 25, 2024
marchermans pushed a commit to McModLauncher/modlauncher that referenced this issue Apr 25, 2024
Matyrobbrt added a commit to Matyrobbrt/NeoForge that referenced this issue May 9, 2024
CodexAdrian added a commit to CodexAdrian/NeoForge that referenced this issue May 21, 2024
commit 8ac9f9c
Author: Minecraftschurli <minecraftschurli@gmail.com>
Date:   Tue May 21 15:25:59 2024 +0200

    [Testframework] Fix wrapping GameTestAssertException (neoforged#988)

commit 66197fe
Author: Max <max@someone.ky>
Date:   Sat May 18 20:11:00 2024 +0200

    Add a Fluid Ingredient system as an analogue to vanilla's Ingredient (neoforged#789)

commit b1c3fe0
Author: NeoForged Localizations <machine-l10n@neoforged.net>
Date:   Sun May 19 00:43:32 2024 +0800

    New Crowdin updates (neoforged#972)

commit a7edbae
Author: Sara Freimer <sara@freimer.com>
Date:   Fri May 17 01:32:34 2024 -0500

    Implement equals and hashCode for SizedIngredients (neoforged#965)

commit e9e8af0
Author: Dennis C <xfacthd@gmx.de>
Date:   Fri May 17 08:31:55 2024 +0200

    [1.20.6] Use extensible enum codec and streamcodec for rarity enum (neoforged#958)

commit 986e0e3
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 17 02:28:12 2024 -0400

    Patch in missing LivingJumpEvent for Slime and Camel (neoforged#966)

commit 2bf3073
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 17 02:26:49 2024 -0400

    Pass growing plant blockstate into onCropsGrowPre for various vine blocks (neoforged#967)

commit 0033435
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Fri May 17 02:25:24 2024 -0400

    Fix ComputeCameraAngles event applying roll in global space (neoforged#968)

commit bb3537b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Wed May 15 23:02:02 2024 -0400

    [no ci] Remove PitcherCrop patch TODO (neoforged#963)

commit d80f154
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Wed May 15 23:01:36 2024 -0400

    [no ci] Fixed Bubble Column gametest template size (neoforged#964)

commit c888a68
Author: Luke Bemish <lukebemish@lukebemish.dev>
Date:   Wed May 15 01:29:03 2024 -0500

    [1.20.6] Add KnownPacks for mods (neoforged#901)

commit a28986f
Author: shartte <shartte@users.noreply.github.com>
Date:   Mon May 13 09:13:19 2024 +0200

    Update FML to 3.0.29 (neoforged#957)

commit 2aadb61
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Sat May 11 14:11:06 2024 -0400

    Make StructureTemplate's Palette caches thread safe (neoforged#954)

commit 2bced72
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Sat May 11 13:49:18 2024 -0400

    Address POI memory leak and Generate Command issues (neoforged#937)

    Co-authored-by: embeddedt <42941056+embeddedt@users.noreply.github.com>

commit abc54b7
Author: Sirttas <Sirttas@users.noreply.github.com>
Date:   Sat May 11 19:48:09 2024 +0200

    [Test Framework] Add a check in `StructureTemplateBuilder#set` to prevent placing block outside template bondaries (neoforged#950)

commit 2d93ce5
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Sat May 11 01:28:34 2024 -0400

    Delete ItemModelShaper patch (neoforged#952)

commit 018e104
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Fri May 10 19:58:05 2024 -0400

    Fix more particle culling issues (neoforged#951)

commit 03e346b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:14:37 2024 -0400

    Fix MC-268617 to allow valid filepaths in Minecraft (neoforged#767)

commit fe57823
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:02:54 2024 -0400

    Fire Villager/Wandering Trader trade events on /reload (neoforged#922)

commit d0ed10a
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:02:04 2024 -0400

    Remove Unnecessary Stitcher patch (neoforged#948)

commit a598489
Author: Matyrobbrt <65940752+Matyrobbrt@users.noreply.github.com>
Date:   Fri May 10 14:44:48 2024 +0300

    Bump Mixin to 0.13.4 to fix local variable issues (neoforged#945)

    Fixes neoforged#768

commit 212f760
Author: sciwhiz12 <arnoldnunag12@gmail.com>
Date:   Fri May 10 10:29:47 2024 +0800

    Fix dedicated server GUI never showing up (neoforged#946)

commit 238a273
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Thu May 9 17:07:08 2024 -0400

    Add more accurate culling for single quad particles (neoforged#885)

commit 27c5d7a
Author: Brennan Ward <Bward7864@gmail.com>
Date:   Thu May 9 10:50:55 2024 -0700

    Fix FinalizeSpawnEvent for trial spawners and fix SpawnGroupData propagation (neoforged#880)

    Closes neoforged#783
    Closes neoforged#939

commit 989ed3b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Thu May 9 13:40:34 2024 -0400

    [1.20.6] Fix several NeoForge command crashes and allow chat OpenFile click action on Integrated Server  (neoforged#915)
CodexAdrian added a commit to CodexAdrian/NeoForge that referenced this issue Jun 14, 2024
commit 8ac9f9c
Author: Minecraftschurli <minecraftschurli@gmail.com>
Date:   Tue May 21 15:25:59 2024 +0200

    [Testframework] Fix wrapping GameTestAssertException (neoforged#988)

commit 66197fe
Author: Max <max@someone.ky>
Date:   Sat May 18 20:11:00 2024 +0200

    Add a Fluid Ingredient system as an analogue to vanilla's Ingredient (neoforged#789)

commit b1c3fe0
Author: NeoForged Localizations <machine-l10n@neoforged.net>
Date:   Sun May 19 00:43:32 2024 +0800

    New Crowdin updates (neoforged#972)

commit a7edbae
Author: Sara Freimer <sara@freimer.com>
Date:   Fri May 17 01:32:34 2024 -0500

    Implement equals and hashCode for SizedIngredients (neoforged#965)

commit e9e8af0
Author: Dennis C <xfacthd@gmx.de>
Date:   Fri May 17 08:31:55 2024 +0200

    [1.20.6] Use extensible enum codec and streamcodec for rarity enum (neoforged#958)

commit 986e0e3
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 17 02:28:12 2024 -0400

    Patch in missing LivingJumpEvent for Slime and Camel (neoforged#966)

commit 2bf3073
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 17 02:26:49 2024 -0400

    Pass growing plant blockstate into onCropsGrowPre for various vine blocks (neoforged#967)

commit 0033435
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Fri May 17 02:25:24 2024 -0400

    Fix ComputeCameraAngles event applying roll in global space (neoforged#968)

commit bb3537b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Wed May 15 23:02:02 2024 -0400

    [no ci] Remove PitcherCrop patch TODO (neoforged#963)

commit d80f154
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Wed May 15 23:01:36 2024 -0400

    [no ci] Fixed Bubble Column gametest template size (neoforged#964)

commit c888a68
Author: Luke Bemish <lukebemish@lukebemish.dev>
Date:   Wed May 15 01:29:03 2024 -0500

    [1.20.6] Add KnownPacks for mods (neoforged#901)

commit a28986f
Author: shartte <shartte@users.noreply.github.com>
Date:   Mon May 13 09:13:19 2024 +0200

    Update FML to 3.0.29 (neoforged#957)

commit 2aadb61
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Sat May 11 14:11:06 2024 -0400

    Make StructureTemplate's Palette caches thread safe (neoforged#954)

commit 2bced72
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Sat May 11 13:49:18 2024 -0400

    Address POI memory leak and Generate Command issues (neoforged#937)

    Co-authored-by: embeddedt <42941056+embeddedt@users.noreply.github.com>

commit abc54b7
Author: Sirttas <Sirttas@users.noreply.github.com>
Date:   Sat May 11 19:48:09 2024 +0200

    [Test Framework] Add a check in `StructureTemplateBuilder#set` to prevent placing block outside template bondaries (neoforged#950)

commit 2d93ce5
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Sat May 11 01:28:34 2024 -0400

    Delete ItemModelShaper patch (neoforged#952)

commit 018e104
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Fri May 10 19:58:05 2024 -0400

    Fix more particle culling issues (neoforged#951)

commit 03e346b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:14:37 2024 -0400

    Fix MC-268617 to allow valid filepaths in Minecraft (neoforged#767)

commit fe57823
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:02:54 2024 -0400

    Fire Villager/Wandering Trader trade events on /reload (neoforged#922)

commit d0ed10a
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Fri May 10 12:02:04 2024 -0400

    Remove Unnecessary Stitcher patch (neoforged#948)

commit a598489
Author: Matyrobbrt <65940752+Matyrobbrt@users.noreply.github.com>
Date:   Fri May 10 14:44:48 2024 +0300

    Bump Mixin to 0.13.4 to fix local variable issues (neoforged#945)

    Fixes neoforged#768

commit 212f760
Author: sciwhiz12 <arnoldnunag12@gmail.com>
Date:   Fri May 10 10:29:47 2024 +0800

    Fix dedicated server GUI never showing up (neoforged#946)

commit 238a273
Author: embeddedt <42941056+embeddedt@users.noreply.github.com>
Date:   Thu May 9 17:07:08 2024 -0400

    Add more accurate culling for single quad particles (neoforged#885)

commit 27c5d7a
Author: Brennan Ward <Bward7864@gmail.com>
Date:   Thu May 9 10:50:55 2024 -0700

    Fix FinalizeSpawnEvent for trial spawners and fix SpawnGroupData propagation (neoforged#880)

    Closes neoforged#783
    Closes neoforged#939

commit 989ed3b
Author: TelepathicGrunt <40846040+TelepathicGrunt@users.noreply.github.com>
Date:   Thu May 9 13:40:34 2024 -0400

    [1.20.6] Fix several NeoForge command crashes and allow chat OpenFile click action on Integrated Server  (neoforged#915)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Needs triaging and confirmation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant