outfox / fennecs

... the tiny C# ECS that loves you back!
https://fennecs.tech
MIT License
223 stars 10 forks source link

Fixed a bug that would arise from reading junk data off shared array buffers. #29

Closed Naalunth closed 2 weeks ago

Naalunth commented 2 weeks ago

This minimal program on its own currently reproduces the bug fixed in this pull request every single time.

using System.Buffers;
using fennecs;

// I'm storing some junk in the shared pool here, so it will get picked up later for a _limiter.
var rentedArrays = Enumerable.Range(0, 2)
    .Select(_ =>
    {
        var rent = ArrayPool<int>.Shared.Rent(2);
        rent[1] = 2;
        return rent;
    })
    .ToList();

// Return out arrays, so fennecs can play with them later.
foreach (var rentedArray in rentedArrays) ArrayPool<int>.Shared.Return(rentedArray);

var world = new World();
world.Spawn().Add<int>();
// There is exactly one Entity here!

var counter = 0;
world.Stream<int>().For((ref int _) => counter++);
Console.WriteLine($"Done. Entities processed: {counter}"); // This prints 2 right now!
Console.WriteLine($"Entities in world: {world.Count}"); // And there is still only 1 Entity.

The problem was that ArrayPool<T>.Rent may return longer arrays than expected. Further down, the length of the arrays was used for logic, without clearing junk data that might have still been in there. In the program where I discovered the bug, this led to a Stream running millions of iterations on a single Entity, and executing the according side effects on every iteration.

thygrrr commented 2 weeks ago

Wow, great find! I need to build a test for this and immediately fix it. (well you already did) (I initially thought this was something I did with the introduction of ArrayPools for Storages)

I wanted to move away from the ArrayPool.Shared, thanks very much for submitting this Issue and PR! I need to wrap my head around what's really going on (the ArrayPool was used because stackalloc arrays caused the JIT to stop inlining).

thygrrr commented 2 weeks ago

Thank you very much for this significant contribution! 💙