I hadn’t run the code in question in a few weeks, and in that time I upgraded Entities and went from 2020.1 beta13 to beta16. I suspect codegen but could be a change in the recent beta I guess.
Pinvoke calls that return an integer started to return the sizeof the integer in Foreach jobs using Schedule. Using Run it works fine. Haven’t tested Job.WithCode.
I started logging the IntPtr values on creation and where they are used. And sure enough in a ForEach job with Schedule they get changed. Run they don’t get touched. These are private so it’s not like some random code could be modifying them.
Guessing maybe pointers moving around happens somewhere with native collections or something, and that logic leaked out in areas it shouldn’t?
There is a pattern here if that helps at all. The first line is the main thread and the value never changes on that. The others are logged from inside the job. First line inside Execute just logs the IntPtr and returns.
I was able to repro it just using a hand created IntPtr, ie new with some big number. But only in the context of this one job.
I consistently see 4 wrong values in the job.
Passing it in via a NativeArray I see one wrong value that way instead of 4 different wrong values.
What does work is grab the IntPtr or a void* from a static in the job.
Testing I’m logging and returning immediately in Execute. Only code I’ve written in the path is instantiate the job struct and Foreach, and then log and return in Execute.
It does seem to be specific to this job. Tried for a couple of hours to get an isolated repro without any luck.
Spoke too soon. This time it hit in a place where an assertion on the ptr on the C side asserted. Different pointer one of two that get passed to native code. So maybe it’s not codegen related.
I have extensive unit tests in .net CORE on these libraries. And they haven’t changed a bit not even how/where it’s used in Unity. Would be nice if someone at Unity would check to see what might have changed that could be causing this. It has to be some change.
Disabling burst was the first thing I did, none of these tests are using burst. The one thing that is consistent is pointers get corrupted inside a threaded job, but not via run. And the job has always been schedule single not parallel. Literally I log the line before I create the job struct schedule it ,and then log immediately inside Execute and return. And somewhere in between it’s being changed.
Ok so it’s not specific to pointers. Now I can just assign an arbitrary int/long and in Execute it’s something different. But it’s something magical about this specific job I still cannot repro it elsewhere.
Ok finally got a break and have a repro. It appears to be the specific combination of BufferFromEntity and NativeDisableContainerSafetyRestriction. The debug will spit out different values then what was set for the long values.
Probably avoidable by not passing the buffer like I am the code is fairly old.
This is on 2020.1 b16 Entities 0.11.1-preview4. Collections is in dev so we can have a newer CompilerServices.Unsafe that’s the only custom mods I can think of that would matter. Rest are higher level feature stuff.
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
namespace AiNav
{
[InternalBufferCapacity(16)]
public struct Bug1TestBuffer : IBufferElementData
{
public static implicit operator float3(Bug1TestBuffer e) { return e.Value; }
public static implicit operator Bug1TestBuffer(float3 e) { return new Bug1TestBuffer { Value = e }; }
public float3 Value;
}
public unsafe struct Bug1TestJob
{
public long A;
public long B;
[NativeDisableContainerSafetyRestriction]
public BufferFromEntity<Bug1TestBuffer> Lookup;
public void Execute()
{
Debug.LogFormat("Withcode {0} {1}", A, B);
}
}
//[DisableAutoCreation]
[AlwaysUpdateSystem]
public class Bug1TestSystem : SystemBase
{
protected override unsafe void OnCreate()
{
base.OnCreate();
}
protected override void OnDestroy()
{
base.OnDestroy();
}
protected override unsafe void OnUpdate()
{
long a = 123456789223;
long b = 4234234234234;
Bug1TestJob job1 = new Bug1TestJob()
{
A = a,
B = b,
Lookup = GetBufferFromEntity<Bug1TestBuffer>(false)
};
Job
.WithoutBurst()
.WithCode(() =>
{
job1.Execute();
}).Schedule();
}
}
}
That is a fascinating repo which I can confirm does as you say, A gets a different value each frame, but as soon as you remove [NativeDisableContainerSafetyRestriction] the error no longer happens.
The codegen matches exactly the same, so it’s only the safety system injection that is causing issues.
If you reorder the fields so A/B come after the lookup, it works fine as well
[NativeDisableContainerSafetyRestriction]
public BufferFromEntity<Bug1TestBuffer> Lookup;
public long A;
public long B;
Works as expected
Conveniently I’ve always ordered my other fields at the end, and from memory this is how Unity tends to order all their code which is why it probably slipped past, but this should work as expected.
-edit-
Still happens if you replace the long with integers
Nice thanks for that discovery. I had another variant where ints didn’t come through at all, and I’ve seen both or just one value be bad. Really strange bug.
Yeah, this looks like a known regression that snuck in as part of an earlier fix for [NativeDisableContainerSafetyRestriction], which previously wasn’t working at all on Buffer-related fields. Specifically, applying this attribute to fields at a non-zero offset of the job struct is what’s causing the memory corruption you’re seeing. The regression appeared in 2020.1.0b16, so rolling back to b15 or earlier should avoid it. I’ll update this thread once the backport lands.