Skip to content

Fix off-by-one in alloc_many unintentionally allocating fresh indices#22785

Merged
alice-i-cecile merged 1 commit into
bevyengine:release-0.18.1from
nickbabcock:bevy-0.18-spawn-batch-fix
Feb 4, 2026
Merged

Fix off-by-one in alloc_many unintentionally allocating fresh indices#22785
alice-i-cecile merged 1 commit into
bevyengine:release-0.18.1from
nickbabcock:bevy-0.18-spawn-batch-fix

Conversation

@nickbabcock

Copy link
Copy Markdown
Contributor

Objective

Currently there is an off-by-one bug in alloc_many. spawn_batch would allocate fresh indices instead of reusing freed ones when current_len == free.len().

I don't believe this bug exists on main, hence why this PR is targeting 0.18.1. Please let me know if there is a better way to land this change.

Testing

  • The unit test covers the bug (ie: reverting the change will cause the test to fail).

The condition 'current_len < self.free.len()' should be '<=' to handle
the case where current_len equals free.len() (i.e., when the free list
has exactly the number of entities we need to allocate).

Without this fix, spawn_batch would allocate fresh indices instead of
reusing freed ones when current_len == free.len().
@github-actions

github-actions Bot commented Feb 3, 2026

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-22785

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-ECS Entities, components, systems, and events P-Regression Functionality that used to work but no longer does. Add a test for this! labels Feb 3, 2026
@alice-i-cecile alice-i-cecile added this to the 0.18.1 milestone Feb 3, 2026
@alice-i-cecile alice-i-cecile added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Feb 3, 2026
@alice-i-cecile

Copy link
Copy Markdown
Member

Given that this is fixed on main but we can't cleanly cherrpick an existing fix I think this is the least bad way to do this.

@ElliottjPierce ElliottjPierce left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! My bad.

Funnily enough, I actually made nearly the exact same mistake in the new allocator and had to fix it there too. Shows the importance of good unit tests I guess.

Thanks for finding and fixing this!

@ElliottjPierce ElliottjPierce added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 3, 2026
@alice-i-cecile alice-i-cecile merged commit a74126e into bevyengine:release-0.18.1 Feb 4, 2026
33 checks passed
@kristoff3r

Copy link
Copy Markdown
Contributor

@alice-i-cecile shouldn't the test have been added to main as well, or is it no longer relevant there? I tried it on main and it compiles fine, but it fails when run.

@ElliottjPierce

ElliottjPierce commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@alice-i-cecile shouldn't the test have been added to main as well, or is it no longer relevant there? I tried it on main and it compiles fine, but it fails when run.

We have other tests on main that cover this now. The bug was in the new allocator, but I fixed that and added additional tests. The tests I added sort and dedupe instead of computing the intersection, but same thing really.

The reason this test fails on main is because we have a local_free queue that is always freed to before flushing that to the shared allocator. If you add a flush_freed() after each free in this test, it should work (but we have a problem if it doesn't.)

This local_free exists to reduce how often we need to use atomics on the shared allocator, and it results in a pretty nice performance improvement. But it does mean that tests that depend on entities being allocated in a particular order need to flush_freed().

See also:
#22658
#22672

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior P-Regression Functionality that used to work but no longer does. Add a test for this! S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants