SamboyCoding / Cpp2IL

Work-in-progress tool to reverse unity's IL2CPP toolchain.
MIT License
1.56k stars 178 forks source link

Indexers Decompile Incorrectly #249

Closed ds5678 closed 6 months ago

ds5678 commented 6 months ago

Context

Indexers in dummy dll assemblies apparently do not get decompiled correctly. I use List<T> as an example here, but I could not find any indexer without the problem.

I found this while working on #204. I verified that my work had no effect on this issue.

Game:

The Long Dark v2.26
Windows
2021.3.16f1

Actual

IL

.property instance !T Item()
{
    .get instance !0 System.Collections.Generic.List`1::get_Item(int32)
    .set instance void System.Collections.Generic.List`1::set_Item(int32, !0)
}

.method public final hidebysig specialname newslot virtual 
    instance !T get_Item (
        int32 index
    ) cil managed 
{
    // Method begins at RVA 0x20730
    // Header size: 12
    // Code size: 12 (0xc)
    .maxstack 1
    .locals (
        [0] !T
    )

    IL_0000: ldloca 0
    IL_0004: initobj !T
    IL_000a: ldloc.0
    IL_000b: ret
} // end of method List`1::get_Item

.method public final hidebysig specialname newslot virtual 
    instance void set_Item (
        int32 index,
        !T 'value'
    ) cil managed 
{
    // Method begins at RVA 0x1b4ab
    // Header size: 1
    // Code size: 1 (0x1)
    .maxstack 8

    IL_0000: ret
} // end of method List`1::set_Item

C

public T Item
{
    get
    {
        return default(T);
    }
    set
    {
    }
}

Expected

IL

This was taken from an API assembly, so ignore the method body content. I suspect the cause of our issue is this second line int32 index which does not appear in the IL above.

.property instance !T Item(
    int32 index
)
{
    .get instance !0 System.Collections.Generic.List`1::get_Item(int32)
    .set instance void System.Collections.Generic.List`1::set_Item(int32, !0)
}

.method public final hidebysig specialname newslot virtual 
    instance !T get_Item (
        int32 index
    ) cil managed 
{
    // Method begins at RVA 0xca6e
    // Header size: 1
    // Code size: 2 (0x2)
    .maxstack 8

    IL_0000: ldnull
    IL_0001: throw
} // end of method List`1::get_Item

.method public final hidebysig specialname newslot virtual 
    instance void set_Item (
        int32 index,
        !T 'value'
    ) cil managed 
{
    // Method begins at RVA 0xca71
    // Header size: 1
    // Code size: 1 (0x1)
    .maxstack 8

    IL_0000: ret
} // end of method List`1::set_Item

C

public T this[int index]
{
    get
    {
        return default(T);
    }
    set
    {
    }
}
SamboyCoding commented 6 months ago

I believe this is also affected by the presence of a DefaultMemberAttribute on the class, which the compiler would usually generate for you