Skip to content

Incorrect handling of boxed types when passed to method with generic argument #207

@furrycoding

Description

@furrycoding

Il2CppInterop version: 1.4.6-ci.579+9d4599dc78d69ede49a2ee96a1ccf41eec02db5b

Example of a method: Dictionary<string, object>.Add(string key, object value)
When a boxed bool is passed as the second argument and later retrieved(with this[string key]), the pointer to it ends up getting shifted 16 bytes forward, which causes even a .ToString() call to crash

The problem seems to be here in the decompilation of the generated Add method:

ref TValue val2;
if (!typeof(TValue).IsValueType)
{
    object obj2 = value;
    System.IntPtr intPtr2;
    if (!(obj2 is string))
    {
        intPtr2 = IL2CPP.Il2CppObjectBaseToPtr(obj2 as Il2CppObjectBase);
        val2 = intPtr2;
        if (intPtr2 != (System.IntPtr)0 && IL2CPP.il2cpp_class_is_valuetype(IL2CPP.il2cpp_object_get_class(intPtr2)))
        {
            intPtr2 = IL2CPP.il2cpp_object_unbox(intPtr2);
            val2 = intPtr2;
        }
    }
    else
    {
        intPtr2 = IL2CPP.ManagedStringToIl2Cpp(obj2 as string);
        val2 = intPtr2;
    }
}
else
{
    val2 = ref value;
}

The correct behavior in this case is to bypass that call to IL2CPP.il2cpp_object_unbox

A quick and dirty fix is to just temporarily overwrite the class pointer of the object passed as the argument, like this:

unsafe {
    // The class pointer is the first field in every il2cpp object struct
    *(IntPtr*)targetObject.Pointer.ToPointer() = Il2CppClassPointerStore<string>.NativeClassPtr;;
}

With that hack, Dictionary behaves as it should, returning a valid boxed object

I'm not sure what the purpose of that unboxing is, but it is pretty clearly the incorrect behavior in this case

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions