benf.org :  other :  cfr :  Renaming fields - (For obfuscation or otherwise).

I finally got around to handling this in CFR 0.92 - use '--renamedupmembers true'

nb: This is related to, but different from illegal field/method names and duplicate method renaming

Some decompiled code occasionally ends up with the same field name repeated multiple times - i.e.

/*
 * Duplicate member names - consider using --renamedupmembers true
 */
public class NameTest22 {
    public float fred;
    public int fred;
    public long fred;

    public NameTest22(int n) {
        this.fred = n + 1;
        this.fred = n + 3;
        this.fred = n + 4;
    }

    public String toString() {
        return "NameTest22{fred=" + this.fred + ", free=" + this.fred + ", fref=" + this.fred + '}';
    }

    public static void main(String[] arrstring) {
        System.out.println(new NameTest22(3));
    }
}

(To reproduce this from legit java, you could (a) simply (as I have) use a hex editor to rename fields 'free' and 'fref' to 'fred', or (b) change the constpool entries so that they all point to the one 'fred' string.)

Using the excellent Hex-fiend editor

There are many fine class file editors out there, but that's sort of out of scope!

The issue here is that these fields now apparently have exactly the same name - that's illegal java!

So why is it ok?

The JVM spec section 5.4.3.2 says the following: If C declares a field with the name and descriptor specified by the field reference, field lookup succeeds.

Note - BOTH name and descriptor (type information) are used for the JVM to uniquely identify a field. This means that according to the JVM, it's perfectly legitimate to have two fields of a different type with the same name. It's just an example where the constraints of the java language are slightly tighter than the constraints of the JVM.

What about if the types were the same too?

Nope. Sad JVM - which is of course entirely consistent with the specification above.

Exception in thread "main" java.lang.ClassFormatError: Duplicate field name&signature in class file org/benf/cfr/tests/NameTest22
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:760)

So why might someone do this?

Obfuscation?

Maybe a bit much - I think this is about as effective an obfuscation as turning a sign saying 'Top secret base this way' upside down.

Compression...

This one seems much more likely to me! In my example above, I hacked existing symbols so they had the same text. However, it would be equivalent to remove the duplicate symbols from the Const Pool altogether - which (obviously!) saves some space. Not much, but perhaps in the world of Mobile Java, this is still a thing worth having.

So how do I read this code?

CFR will now decorate any class file it thinks suffers from this issue with this comment

/*
 * Duplicate member names - consider using --renamedupmembers true
 */

So.... just do that! Because the types of the fields are part of the key, this flag appends _type to any duplicate field.

/*
 * Decompiled with CFR
 */
package org.benf.cfr.tests;

import java.io.PrintStream;

public class NameTest22 {
    public float fred_float;
    public int fred_int;
    public long fred_long;

    public NameTest22(int n) {
        this.fred_int = n + 1;
        this.fred_float = n + 3;
        this.fred_long = n + 4;
    }

    public String toString() {
        return "NameTest22{fred=" + this.fred_float + ", free=" + this.fred_int + ", fref=" + this.fred_long + '}';
    }

    public static void main(String[] arrstring) {
        System.out.println(new NameTest22(3));
    }
}

Please note: CFR will not automatically enable this flag.

Great! But why not always run with this flag on?

Two reasons:


Last updated 01/2015