"AtomicSafetyNode has either been corrupted" error when trying to access a component value

I’m not sure I understand why this (stripped down) code is throwing errors:

AtomicSafetyNode has either been corrupted or is being accessed on a job which is not allowed.

and

ObjectDisposedException: The Unity.Collections.NativeArray`1[System.Int32] has been deallocated, it is not allowed to access it

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using UnityEngine;

public partial struct TestingStuffA : ISystem
{
   public void OnUpdate(ref SystemState state)
   {
      state.Enabled = false;
      var data = new MyData(1);
      var job = new MyJob
      {
         ECB = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>().CreateCommandBuffer(state.WorldUnmanaged),
         Data = data
      };
      state.Dependency = job.Schedule(state.Dependency);
   }
}

public struct MyJob : IJob
{
   public EntityCommandBuffer ECB;
   public MyData Data;

   public void Execute()
   {
      var entity = ECB.CreateEntity();
      ECB.AddComponent<MyComponent>(entity, new MyComponent { Data = Data });
   }
}

public struct MyData
{
   public NativeArray<int> Values;

   public MyData(int value)
   {
      Values = new NativeArray<int>(value, Allocator.Persistent);
      for (int i = 0; i < Values.Length; i++)
      {
         Values[i] = value;
      }
   }
}

public struct MyComponent : IComponentData
{
   public MyData Data;
}

public partial struct TestingStuffB : ISystem
{
   public void OnCreate(ref SystemState state)
   {
      state.RequireForUpdate<MyComponent>();
   }
   public void OnUpdate(ref SystemState state)
   {
      var component = SystemAPI.GetSingleton<MyComponent>();
      Debug.Log("Testing Value: " + component.Data.Values[0]);
   }
}

Same errors if I try to Run, or RunByRef, also tried to pass the component in for the ECB to add.

using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Unity.Jobs;
using UnityEngine;

public partial struct TestingStuffA : ISystem
{
   public void OnUpdate(ref SystemState state)
   {
      state.Enabled = false;
      var data = new MyData(1);
      var singleton = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
      var ecb = singleton.CreateCommandBuffer(state.WorldUnmanaged);
      var job = new MyJob
      {
         ECB = ecb,
         Data = new MyComponent { Data = data }
      };
      job.Run();
   }
}

public struct MyJob : IJob
{
   public EntityCommandBuffer ECB;
   [ReadOnly] public MyComponent Data;

   public void Execute()
   {
      var entity = ECB.CreateEntity();
      ECB.AddComponent<MyComponent>(entity, Data);
   }
}

public struct MyData
{
   public NativeArray<int> Values;

   public MyData(int value)
   {
      Values = new NativeArray<int>(value, Allocator.Persistent);
      for (int i = 0; i < Values.Length; i++)
      {
         Values[i] = value;
      }
   }
}

public struct MyComponent : IComponentData
{
   public MyData Data;
}

public partial struct TestingStuffB : ISystem
{
   public void OnCreate(ref SystemState state)
   {
      state.RequireForUpdate<MyComponent>();
   }
   public void OnUpdate(ref SystemState state)
   {
      var component = SystemAPI.GetSingleton<MyComponent>();
      Debug.Log("Testing Value: " + component.Data.Values[0]);
   }
}

ok I just realised it’s probably because I have a NativeArray in IComponentData (not blittable).

You can have NativeXXX containers in components, but you can’t access them inside job from component AND (initial issue in your case) you can’t allocate them with Persistent allocator inside job. NativeXXX containers can only be allocated with Temp memory allocator inside job for in place use. If you need allocate container for future use inside job and you want to store it on component and you want to access this data in the future from that component also inside job - use UnsafeXXX containers (or directly have pointer and malloc memory), which you can allocate with Persistent memory inside job, but all safety and leaks tracking is up to you.

The issue is that passing the array to the job (through MyComponent) causes the safety system to update the safety info in the array that temporarily messes with your ability to access it. You can sidestep the safety system doing this by wrapping it in a NativeReference like this:

public partial struct TestingStuffA : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        state.Enabled = false;
        var data = new MyData(1);
        var singleton = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
        var ecb = singleton.CreateCommandBuffer(state.WorldUnmanaged);
        NativeReference<MyComponent> reference = new(state.WorldUpdateAllocator);
        reference.Value = new MyComponent { Data = data };
        var job = new MyJob
        {
            ECB = ecb,
            Data = reference
        };
        state.Dependency = job.Schedule(state.Dependency);
    }
}

public struct MyJob : IJob
{
    public EntityCommandBuffer ECB;
    [NativeDisableContainerSafetyRestriction] public NativeReference<MyComponent> Data;

    public void Execute()
    {
        var entity = ECB.CreateEntity();
        ECB.AddComponent<MyComponent>(entity, Data.Value);
    }
}

This seems to function on my end with no errors or thrown exceptions.