Bug with initialization of struct with explicitly sized enums in Editor release mode

Burst Version: 1.7.1

Scenario: This only seems to repro when the editor is set to release mode (the button in the bottom right corner).

If you throw the following script in the scene, you’ll see that the non-bursted code prints true while the bursted code prints false.

using System;
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;

[ExecuteAlways]
public class BurstTest : MonoBehaviour
{
    private enum Enum1 : ushort
    {
        Val1 = 0,
        Val2 = 1,
        Val3 = 2 * Val2,
        Val4 = 2 * Val3,
        Val5 = 2 * Val4,
        Val6 = 2 * Val5,
    }

    private enum Enum2
    {
        Val1 = 0,
        Val2 = 1,
        Val3 = 2,
        Val4 = 3,
        Val5 = 4,
    }

    private enum Enum3 : byte
    {
        Val1,
        Val2
    }

    private struct Foo : IEquatable<Foo>
    {
        public Enum1 A;
        public Enum2 B;
        public Enum3 C;

        public bool Equals(Foo other)
        {
            return MemUtils.AreEqual(ref this, ref other);
        }
    }

    private static bool CheckEquality()
    {
        Foo a = new Foo()
        {
            A = Enum1.Val2,
            B = Enum2.Val4,
            C = Enum3.Val2
        };
        Foo b = new Foo()
        {
            A = Enum1.Val2,
            B = Enum2.Val4,
            C = Enum3.Val2
        };
        return a.Equals(b);
    }

    [BurstCompile]
    private struct JobEqualityCheck : IJob
    {
        public void Execute()
        {
            Debug.Log($"Bursted: {CheckEquality()}");
        }
    }

    private void OnEnable()
    {
        Debug.Log($"Not bursted: {CheckEquality()}");
        new JobEqualityCheck().Run();
    }

    private unsafe static class MemUtils
    {
        public static bool AreEqual<T>(ref T a, ref T b) where T : unmanaged
        {
            fixed (T* ptr1 = &a)
            {
                fixed (T* ptr2 = &b)
                {
                    return UnsafeUtility.MemCmp(ptr1, ptr2, UnsafeUtility.SizeOf<T>()) == 0;
                }
            }
        }
    }
}

Actually, maybe this isn’t a burst bug and it’s just the fact that burst skips zeroing out the struct on creation in release mode? So it’s actually a bug (on my end) with using memcmp on a struct which has any padding. It’s easy to work around this issue by not using memcmp, but I thought it might be worth posting just in case.

Yes, your assessment is correct, that’s exactly what’s happening.

Interesting, I thought that sort of behavior could only happen if you used the SkipLocalsInit Attribute?

Is the reasoning for not zeroing out the padding as well that technically the padding is not a variable?

2 Likes