Skip to content

Update getBodiesUnsafe() to return a slice of size getMaxBodies()#25

Open
r0ckHopper wants to merge 3 commits into
zig-gamedev:mainfrom
r0ckHopper:main
Open

Update getBodiesUnsafe() to return a slice of size getMaxBodies()#25
r0ckHopper wants to merge 3 commits into
zig-gamedev:mainfrom
r0ckHopper:main

Conversation

@r0ckHopper
Copy link
Copy Markdown

Currently getBodiesUnsafe() returns a slice of size getNumBodies() but getBodiesUnsafe() actually returns a pointer to slice of size max_bodies.

The issue comes when you delete bodies from the middle and try to access bodies of higher index

getBodiesUnsafe does not reorganize the elements before giving a slice so you can get an out of bounds error

example of the issue is:

let bodies be
[b0, b1, b2]

if you delete b1 jolt physics updates bodies to
[b0, invalid, b2]

but if you call getBodiesUnsafe you only get
[b0, invalid]

so if you do tryGetBody( all_bodies, b2) then it will look for b2 at index 2 which is out of bounds

getBodiesUnsafe() returned ptr[0..getNumBodies()] but its values can go
upto 1024 (getMaxBodies)
After destroying bodies, the active count shrinks but remaining bodies stay at the same slots, causing out-of-bounds exceptions.
The underlying Jolt array also uses max_bodies, so slicing to getMaxBodies() is safe.
Same issue as addressed in commit 77a907d
getBodiesMutUnsafe() returned ptr[0..getNumBodies()] but its values can go
upto 1024 (getMaxBodies)
After destroying bodies, the active count shrinks but remaining bodies stay at the same slots, causing out-of-bounds exceptions.
The underlying Jolt array also uses max_bodies, so slicing to getMaxBodies() is safe.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an API mismatch where PhysicsSystem.getBodiesUnsafe() / getBodiesMutUnsafe() returned a slice sized to getNumBodies() even though the underlying Jolt buffer is sized to max_bodies, which could cause out-of-bounds indexing when accessing bodies by BodyId after deletions create holes.

Changes:

  • Return a getMaxBodies()-sized slice from getBodiesUnsafe() and getBodiesMutUnsafe().
  • Add a regression test covering the “destroy middle body then index by BodyId” scenario.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/zphysics.zig
Comment on lines 1546 to +1550
pub fn getBodiesUnsafe(physics_system: *const PhysicsSystem) []const *const Body {
const ptr = c.JPC_PhysicsSystem_GetBodiesUnsafe(
@as(*c.JPC_PhysicsSystem, @ptrFromInt(@intFromPtr(physics_system))),
);
return @as([*]const *const Body, @ptrCast(ptr))[0..physics_system.getNumBodies()];
return @as([*]const *const Body, @ptrCast(ptr))[0..physics_system.getMaxBodies()];
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Which doc is Copilot referencing? Is it the comment above the function?

Comment thread src/zphysics.zig
Comment on lines 1552 to 1556
/// NOTE: Advanced. This function is *not* protected by a lock, use with care!
pub fn getBodiesMutUnsafe(physics_system: *PhysicsSystem) []const *Body {
const ptr = c.JPC_PhysicsSystem_GetBodiesUnsafe(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
return @as([*]const *Body, @ptrCast(ptr))[0..physics_system.getNumBodies()];
return @as([*]const *Body, @ptrCast(ptr))[0..physics_system.getMaxBodies()];
}
Comment thread src/zphysics.zig
Comment on lines +4523 to +4528
const physics_system = try PhysicsSystem.create(
@as(*const BroadPhaseLayerInterface, @ptrCast(&test_cb1.MyBroadphaseLayerInterface.init())),
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&test_cb1.MyObjectVsBroadPhaseLayerFilter{})),
@as(*const ObjectLayerPairFilter, @ptrCast(&test_cb1.MyObjectLayerPairFilter{})),
.{ .max_bodies = 1024, .num_body_mutexes = 0, .max_body_pairs = 1024, .max_contact_constraints = 1024 },
);
Comment thread src/zphysics.zig
Comment on lines +4557 to +4561
const all_bodies = physics_system.getBodiesMutUnsafe();

//following should not throw panic
//zig does not have panic handler for unit tests so best we can do is test happy path or crash program
_ = tryGetBody(all_bodies, b2);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That runs counter to the intention of the test. Checking if null does not assert that no panic is thrown (which is a zig limitation, that panic cannot be caught). So only option right now is to test happy path or remove test entirely.

Ideally there would be try catch for panic, and if panic is caught then test fails.

Comment thread src/zphysics.zig
const b1 = try body_interface.createAndAddBody(settings, .activate);
const b2 = try body_interface.createAndAddBody(settings, .activate);

_ = b0; //just to rid of compiler error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants