PyBullet saveWorld resurrects a removed object after body-ID reuse
Environment
- OS: Ubuntu 24.04.5 LTS, Linux 7.0.0-28-generic x86_64
- Compiler: GCC 11.5.0
- Python: 3.12.3
- Source:
bulletphysics/bullet3masterat63c4d67e337017f9d8b298c900e9aabdb69296e7 - PyBullet: built locally from that exact checkout
Description
PyBullet records imported filenames and body IDs in m_saveWorldBodyData. removeBody frees the body handle but leaves its ID in that serialization metadata. When a later object reuses the ID, saveWorld resolves the stale record through the replacement and serializes both assets at the replacement's pose.
Expected behavior: saveWorld emits only objects that are live at save time.
Actual behavior: the reproducer loads cube.urdf as body 0, removes it, and loads sphere2.urdf at x=5 as reused body 0. The saved program contains both a cube load and a sphere load, each at x=5. Replaying it therefore resurrects the deleted cube.
Sources:
- metadata creation: https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L3198-L3230
- serialization: https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L4389-L4465
- removal: https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L12739-L12947
Reproduction package:
save-world-removed-body-id-poc.zip
Steps to reproduce
- Build PyBullet from the commit above using
poc/README.md. - Run
python poc/reproducer.py. - Inspect the printed
loadURDFlines and the generatedsaved_world.py.
Observed output is in poc/observed-output.txt.
Source: bulletphysics/bullet3