Il2CppInterop icon indicating copy to clipboard operation
Il2CppInterop copied to clipboard

Injected class fields are collected

Open limoka opened this issue 3 years ago • 0 comments

Issue

Any fields in injected classes are being collected by garbage collector. This includes both fields coming from parent classes, and injected ones.

Fields which store a class, which is also stored somewhere, where it is recognized by garbage collector stops that. For example any Unity Game Objects and Components are not collected, as they are stored in Unity hierarchy.

When this happens field's wasCollected property is never set, in fact the object is replaced by some random allocated object. This causes severe data corruption if such classes are introduced into game state.

Steps to Reproduce

Create an injected class like this, and add it to any Game Object on Load()

public class TestClass : MonoBehaviour
{
    public Il2CppReferenceField<List<MyClass>> myClassList;

    public TestClass(IntPtr ptr) : base(ptr) { }

    private GCHandle myClassListHandle;

    private void Awake()
    {
	// In awake I initialize the field
        List<MyClass> list = new List<MyClass>();
	// Remove this line to remove the temporary fix
        myClassListHandle = GCHandle.Alloc(list, GCHandleType.Normal);
        myClassList.Set(list);
    }

    private void OnDestroy()
    {
	// Remove this line to remove the temporary fix
        myClassListHandle.Free();
    }
}

MyClass can be any class. For example a AudioClip, or some other serialized class.

Now check the value of the myClassList field after the game has loaded fully. It will contain garbage object, which is likely is not even related to original class. It will not contain any data you store there.

In the snippet I also included a temporary fix I found. If I create a GCHandle for my field object, it will not get collected.

limoka avatar Aug 23 '22 06:08 limoka