Unexpected and inconsistent NaN error inside a job

I wrote a job to update values on entities based on an event struct which has the startTime, endTime, start and end fields.

I made a method which should return math.lerp(start, end, math.unlerp(startTime, endTime, currentTime)). (The real method checks whether startTime == endTime is true and uses 0 to avoid NaN errors.)

And yet, I came across NaN errors while updating transform positions for entities.
And while I tried to find out the cause, I noticed that the errors don’t always appear depending on what I write even though I did not change the logic, only added Debug.Logs.

So, I made a test method to confirm my suspicions.

        private readonly float GetEVV(TimedEvent @event)
        {
#if DEBUG
            Debug.Assert(!math.isnan(@event.startTime), $"{nameof(@event.startTime)} is nan");
            Debug.Assert(!math.isnan(@event.endTime), $"{nameof(@event.endTime)} is nan");
            Debug.Assert(!math.isnan(@event.start), $"{nameof(@event.start)} is nan");
            Debug.Assert(!math.isnan(@event.end), $"{nameof(@event.end)} is nan");
#endif
            float t = @event.startTime == @event.endTime
            ? 0
            : (currentTime - @event.startTime) / (@event.endTime - @event.startTime);//math.unlerp(@event.startTime, @event.endTime, currentTime);
            //float v = math.lerp(@event.start, @event.end, t);
            float v = @event.start + t * (@event.end - @event.start);
#if DEBUG
            if (math.isnan(v) || math.isnan(t))
            {
                if (math.isnan(v))
                    Debug.LogWarning($"{nameof(v)} is nan");
                if (math.isnan(t))
                    Debug.LogWarning($"{nameof(t)} is nan");
#if false // log them
                if (@event.startTime == @event.endTime)
                {
                    Debug.Log($"{@event.start} + {t} * ({@event.end} - {@event.start})");
                }
                else
                {
                    Debug.Log($"{@event.start} + (({currentTime} - {@event.startTime}) / ({@event.endTime} - {@event.startTime})) * ({@event.end} - {@event.start})");
                }
#endif
            }
#endif
                return v;
        }

And depending on whether I set the #if to true or false on line 21, the value of v and t changes.
If it is false, both become NaN which is strange since t should become 0 if startTime is equal to endTime which is the only one possible case for it to become NaN.


(place of removed image 1)

But if it is true, the value becomes 0 without having any NaN errors.
(place of removed image 2 and 3)

Also, displaying startTime, endTime, start and end to the console with Debug.Log also has a similar effect. It also shows that all of the values are 0 which shouldn’t be the case. So, I attached VS’s debugger to unity and inspected the value with it.
(place of removed image 4)

And just like magic, suddenly, the values aren’t 0 any more.

There were more images here, but discussions didn’t let me use more than 1 attachment since I am a new user.

  • removed image 1: the value of the component is NaN

  • removed image 2: the console is clear, no warnings

  • removed image 3: the value of the component is 0

  • removed image 4: VS’s debugger shows the values under locals

    startTime = -7.788249E-05
    endTime = 4.590934E-41
    start = -7.788127E-05
    end = 4.590934E-41

    The values being the same is probably another bug which I’ll have to fix but the important part is that neither of these values are 0.

I am at my wit’s end here. What am I doing wrong?

I think your TimedEvent has uninitialized memory. Did you get it from a NativeArray that you allocated with uninitialized memory? Or maybe you aliased it wrong somewhere?

nope, the event comes from an EventTracker blob asset which has an initialized BlobArray<EventTracker> in it. Apart from that, I don’t think using uninitialized memory could explain why logging the values can avoid them being nan.

If startTime does not equal endTime but the difference is extremely small then division will result in 0. You could try using double instead of float and see if that solves it?

I tried it but it still didn’t work.

When it comes to uninitialized memory values, the values tend to be a lot less random than you would expect, and tend to correlate to changes in code. It is a weird thing, but I’ve dealt with plenty of uninitialized value bugs and other types of memory corruption.

Anyways, I’m now suspecting that you are passing a BlobArray by value somewhere. This would mean that your garbage data would actually be stack data, which would definitely explain the behavior you are seeing.

I see. that might be the case.

BlobBuilder builder = new(Allocator.Temp);
ref eventTracker tracker = ref builder.ConstructRoot<EventTracker>();
BlobBuilderArray<TimedEvent> eventsBuilder;

Should I have used ref when filling the builder?
Wait, I don’t think that’s right.
Thank you, one way or another, you helped me find the issue.
Yep, I am looking at the docs and I was supposed to initialize it.
And yet, I still get nan values…
Edit: I forgot that eventsBuilder was initialized a few lines down because the length and the first element is determined by a condition.