leibnitz27 / cfr

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

Non-static access to static field #238

Open Kyuuhachi opened 3 years ago

Kyuuhachi commented 3 years ago

CFR version 0.151, javac version 1.8.0_282

Accessing a static field through a non-static expression is compiled by javac as [the expression]; POP; GETSTATIC ...;. It's not always possible to determine whether this was the case or if it's two separate statements, but in some cases it should be possible.

Currently CFR sometimes ignores the expression, generating only a static access. This can cause discrepancies in null tolerance.

This was supposedly fixed by https://github.com/leibnitz27/cfr/commit/14d94c94d37f453e9085c0083d5901480a15af87, but it doesn't seem to be working.

Special care should be taken when shadowing fields, as in test2c and test2d.

Example

class Test2 {
    final Test2 a = this;
    static int PINEAPPLE = 123;
    static int random() { return 4; }
}

class Test2b extends Test2 {
    static int PINEAPPLE = 0;
    final Test2b b = this;
}

class Test2s {
    int test2a(Test2 a) {
        return a.a.random();
    }

    int test2b(Test2 a) {
        return a.a.PINEAPPLE;
    }

    int test2c(Test2b b) {
        return b.b.random();
    }

    int test2d(Test2b b) {
        return ((Test2)b.b).random();
    }
}

Decompiles into

class Test2s {
    Test2s() {
    }

    int test2a(Test2 test2) {
        Test2 test22 = test2;
        return test22.a.random();
    }

    int test2b(Test2 test2) {
        return Test2.PINEAPPLE;
    }

    int test2c(Test2b test2b) {
        Test2b test2b2 = test2b;
        return test2b2.b.random();
    }

    int test2d(Test2b test2b) {
        return Test2.random();
    }
}

In several cases, the expression is dropped entirely, which makes those functions more lenient with nulls.