rapier.js
rapier.js copied to clipboard
recursive use of an object detected which would lead to unsafe aliasing in rust
Using rapier2d-compat version 0.7.6
// World contains some static and dynamic body
world.forEachRigidBody(body =>{
const collidersLength = body.numColliders();
for (let i = 0; i < collidersLength; i++) {
const collider = world.getCollider(body.collider(i));
drawBody(ctx, collider, body);
}
if (body.bodyType() === RAPIER.RigidBodyType.Static) {
return
}
const bodyPosition = body.translation();
const bodyMass = body.mass();
world.forEachRigidBody(otherBody => {
if (body.handle === otherBody.handle) {
return
}
const otherBodyMass = otherBody.mass();
const otherBodyPosition = otherBody.translation();
const distance = getDistance(otherBodyPosition, bodyPosition);
const forceDirection = getDirection(
otherBodyPosition,
bodyPosition
);
const forceMagnitude = getGravitationalForce(
otherBodyMass,
bodyMass,
distance
);
try {
body.applyForce(
new RAPIER.Vector2(
(Math.sin(forceDirection) * forceMagnitude) /
Math.sqrt(bodyMass),
(Math.cos(forceDirection) * forceMagnitude) /
Math.sqrt(bodyMass)
),
true
);
} catch (error) {
console.error(error);
}
})
})
This code always throws as soon as I have 2 bodies (1 static & 1 dynamic, 2 statics, 2 dynamics, whatever) with the error recursive use of an object detected which would lead to unsafe aliasing in rust.

The error also happens with forEachRigidBodyHandle
The same code using forEachCollider works (but I wanna use forEachRigidBody because some bodies have multiple colliders)
world.forEachCollider((collider) => {
const body = world.getRigidBody(collider.parent());
drawBody(ctx, collider, body);
if (body.bodyType() === RAPIER.RigidBodyType.Static) {
return;
}
const bodyPosition = body.translation();
const bodyMass = body.mass();
world.forEachCollider((otherCollider) => {
const otherBody = world.getRigidBody(otherCollider.parent());
if (body.handle === otherBody.handle) {
return;
}
const otherBodyMass = otherBody.mass();
const otherBodyPosition = otherBody.translation();
const distance = getDistance(otherBodyPosition, bodyPosition);
const forceDirection = getDirection(
otherBodyPosition,
bodyPosition
);
const forceMagnitude = getGravitationalForce(
otherBodyMass,
bodyMass,
distance
);
try {
body.applyForce(
new RAPIER.Vector2(
(Math.sin(forceDirection) * forceMagnitude) /
Math.sqrt(bodyMass),
(Math.cos(forceDirection) * forceMagnitude) /
Math.sqrt(bodyMass)
),
true
);
} catch (error) {
console.error(error);
}
});
});
do not modify bodies while the world is supposed to be locked.
@jcyuan I think this info would be super a useful addition to the rigidbody documentation page. Can you please explain when the world is "locked" in the lifecycle of a world.step() and maybe some additional info of best practices to avoid this error in the future? Please and Thank You
@jcyuan I think this info would be super a useful addition to the rigidbody documentation page. Can you please explain when the world is "locked" in the lifecycle of a world.step() and maybe some additional info of best practices to avoid this error in the future? Please and Thank You
that means the world is iterating through all stuffs, and you should not modify the internal list.
so, once the step is called, the world is locked.
for example
world.step -> world now will start to iterate through all bodies
1, do not destroy / create bodies, colliders, joints (probably will break the internal list) 2, do not apply transform on bodies, colliders (probably will break those contacts)
such errors often occur when you try to do so in a contact callback. and do somethings in your timer event callback.
a very simple pseudo-code:
world.step {
foreach(world.bodies) {
contactEvents-> triggerUserCallback();
}
}
triggerUserCallback() {
// do not remove / create bodies (modify the world.bodies list)
}
anyway, not sure what caused his error, because it looks not like a 'locking' problem. i'm sorry i didn't test his code before, but now i have just tested it and it just works fine my side (0.8-alpha.2)
@sebcrozet sir, any conditions i'm missing?
@myagoo btw, can you please test again with the newest lib?
@jcyuan I found out I was starting a new runtime loop before I finished the last due to async/await. So this was indeed the problem. thanks!
Hello, I'm sorry I stopped working on the project for a while but I'm now back at it : Upgrading to latest version (0.10) fixed this issue :)
Thanks for the amazing work.
Just dropping a note here. I don't think there is a notion of "a world is in a locked state or the world is running something"?
I mean once you execute world.step(), that thread (presumably a main thread) will start executing it, run through all Rapier stuff, then stop, and only then continue with whatever tasks you give it. The world.step() will execute synchronously on the thread it was executed on. There is nothing that could possibly get there in between while it is executing that method. If you change a property of some object in the physics world, it will be changed either before or after the world.step(), but never during.
From Rapier point of view, it doesn't know when you are executing world.step(). You could do it once, twice, thrice or as many times as you want per frame. Rapier doesn't know what a frame is, it just knows that you have called world.step and it should simulate the world.
On the other hand, I did meet that error, when Rapier was running in a web worker some releases ago. I am not sure what was causing it, but I haven't used the worker in a while, so haven't met the issue either lately.
Just dropping a note here. I don't think there is a notion of "a world is in a locked state or the world is running something"?
I mean once you execute
world.step(), that thread (presumably a main thread) will start executing it, run through all Rapier stuff, then stop, and only then continue with whatever tasks you give it. Theworld.step()will execute synchronously on the thread it was executed on. There is nothing that could possibly get there in between while it is executing that method. If you change a property of some object in the physics world, it will be changed either before or after theworld.step(), but never during.From Rapier point of view, it doesn't know when you are executing
world.step(). You could do it once, twice, thrice or as many times as you want per frame. Rapier doesn't know what a frame is, it just knows that you have calledworld.stepand it should simulate the world.On the other hand, I did meet that error, when Rapier was running in a web worker some releases ago. I am not sure what was causing it, but I haven't used the worker in a while, so haven't met the issue either lately.
step triggers some event callback, and you try to modify something inside your event handler.
this is syned process (same thread), not asynced.
Ah, of course, you are right on that one. Completely forgot about the event callbacks 😅 I am scheduling all event updates to the next simulation step, thats why I don't have it. I wonder why Ammo doesn't crash, though 🤔 I guess there is some safety mechanism in place to prevent it.