diff options
author | PouleyKetchoupp <pouleyketchoup@gmail.com> | 2021-04-12 20:08:30 -0700 |
---|---|---|
committer | PouleyKetchoupp <pouleyketchoup@gmail.com> | 2021-04-12 20:08:30 -0700 |
commit | d7353c5d413ea9f0c2bfac93c8eca247e43a8d9b (patch) | |
tree | 6b439438e1ec1ce3cd161d5f2dc2a44caa66b4b3 /scene | |
parent | 075f358fcddbb3df8417ef85baabdf3684a4efd2 (diff) |
Fix crashes with CollisionObject debug shapes
MeshInstance added as child nodes for CollisionObject debug shapes can
be invalidated while deleting the collision object (child nodes are
deleted first), which caused accesses to invalid memory in
shape_owner_remove_shape that lead to random crashes.
Also optimized accesses to shapes to avoid copy-on-write on each
iteration.
Diffstat (limited to 'scene')
-rw-r--r-- | scene/3d/collision_object_3d.cpp | 27 | ||||
-rw-r--r-- | scene/3d/collision_object_3d.h | 2 |
2 files changed, 28 insertions, 1 deletions
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 352a793987..261ff5db55 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -75,6 +75,11 @@ void CollisionObject3D::_notification(int p_what) { } } break; + case NOTIFICATION_PREDELETE: { + if (debug_shape_count > 0) { + _clear_debug_shapes(); + } + } break; } } @@ -116,11 +121,13 @@ void CollisionObject3D::_update_debug_shapes() { for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) { if (shapes.has(shapedata_idx->get())) { ShapeData &shapedata = shapes[shapedata_idx->get()]; + ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); for (int i = 0; i < shapedata.shapes.size(); i++) { - ShapeData::ShapeBase &s = shapedata.shapes.write[i]; + ShapeData::ShapeBase &s = shapes[i]; if (s.debug_shape) { s.debug_shape->queue_delete(); s.debug_shape = nullptr; + --debug_shape_count; } if (s.shape.is_null() || shapedata.disabled) { continue; @@ -133,12 +140,30 @@ void CollisionObject3D::_update_debug_shapes() { add_child(mi); mi->force_update_transform(); s.debug_shape = mi; + ++debug_shape_count; } } } debug_shapes_to_update.clear(); } +void CollisionObject3D::_clear_debug_shapes() { + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + ShapeData &shapedata = E->get(); + ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); + for (int i = 0; i < shapedata.shapes.size(); i++) { + ShapeData::ShapeBase &s = shapes[i]; + if (s.debug_shape) { + s.debug_shape->queue_delete(); + s.debug_shape = nullptr; + --debug_shape_count; + } + } + } + + debug_shape_count = 0; +} + void CollisionObject3D::_update_shape_data(uint32_t p_owner) { if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) { if (debug_shapes_to_update.is_empty()) { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index a2a0cbf988..e2f6cc7500 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -62,6 +62,7 @@ class CollisionObject3D : public Node3D { bool ray_pickable = true; Set<uint32_t> debug_shapes_to_update; + int debug_shape_count = 0; void _update_pickable(); @@ -78,6 +79,7 @@ protected: virtual void _mouse_exit(); void _update_debug_shapes(); + void _clear_debug_shapes(); public: uint32_t create_shape_owner(Object *p_owner); |