leibnitz27 / cfr

This is the public repository for the CFR Java decompiler
https://www.benf.org/other/cfr
MIT License
1.93k stars 249 forks source link

CFR incorrectly decompiles stack values being reordered #332

Open NeRdTheNed opened 1 year ago

NeRdTheNed commented 1 year ago

CFR version

CFR 0.152 / CFR 0.153-SNAPSHOT (d6f6758)

Compiler

Jasmin / generated bytecode

Description

This example conditionally changes the order of the current 3 values on the stack, swapping the first and last values. In the decompiled output when bl is false, the values of n6 and n4 are not swapped properly, as it instead overwrites n4 with the value of n6 only. I noticed this when generating JVM bytecode for a project, I'm unsure if the Java compiler would output something like this naturally. This bug report is based on a report I wrote up for QuiltFlower (QuiltMC/quiltflower#216), which also has a similar issue when decompiling this .class file.

Example

Jasmin example code:

.class public com/example/Bug
.super java/lang/Object

.method private <init>()V
    aload_0
    invokespecial java/lang/Object/<init>()V
    return
.end method

.method public static bugDemo(IIIZ)I
    .limit stack 4
    .limit locals 4

    iload_0
    iconst_2
    imul

    iload_1
    iconst_2
    imul

    iload_2
    iconst_2
    imul

    ; Swap order of values on stack conditionally
    iload_3
    ifne Target

    ; Order is changed from 0, 1, 2 to 2, 1, 0
    dup_x2
    pop
    swap

Target:

    ineg
    iadd
    iadd
    ireturn
.end method

...and the compiled .class file. And here's the decompiled output (output is the same on CFR 0.153-SNAPSHOT (d6f6758)):

/*
 * Decompiled with CFR 0.152.
 */
package com.example;

public class Bug {
    private Bug() {
    }

    public static int bugDemo(int n, int n2, int n3, boolean bl) {
        int n4 = n * 2;
        int n5 = n2 * 2;
        int n6 = n3 * 2;
        if (!bl) {
            n4 = n6;
            n6 = n4;
            n5 = n5;
        }
        return n4 + (n5 + -n6);
    }
}