From 21778d35ab8329786cc752ba7d8c5402fcd87cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20=C5=BBak?= Date: Tue, 3 Feb 2026 14:48:16 +0100 Subject: [PATCH] use QPointer in QTimer::singleShot to prevent use-after-free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QTimer::singleShot in Property::setModel used model_ as context but captured 'this' (Property*). If the Property was destroyed before the timer fired, this caused a use-after-free crash in the propertyHiddenChanged signal emission. Fix by capturing QPointer guarded 'this'. Semantic stays the same - Qt automatically cancels the timer if the model_ is destroyed but QPointer on Property provides extra protection. The bug manifests as a segfault in MoveIt Setup Assistant when loading robot models, crashing in PropertyTreeModel::propertyHiddenChanged(). Some MoveIt2 crashes seem relevant: - 3546 - 3553 - 3541 Signed-off-by: Mateusz Żak --- rviz_common/src/rviz_common/properties/property.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rviz_common/src/rviz_common/properties/property.cpp b/rviz_common/src/rviz_common/properties/property.cpp index 444ed4531..c325ffeab 100644 --- a/rviz_common/src/rviz_common/properties/property.cpp +++ b/rviz_common/src/rviz_common/properties/property.cpp @@ -37,6 +37,7 @@ #include // NOLINT: cpplint is unable to handle the include order here #include // NOLINT: cpplint is unable to handle the include order here #include // NOLINT: cpplint is unable to handle the include order here +#include // NOLINT: cpplint is unable to handle the include order here #include // NOLINT: cpplint is unable to handle the include order here #include // NOLINT: cpplint is unable to handle the include order here #include // NOLINT: cpplint is unable to handle the include order here @@ -386,10 +387,12 @@ void Property::setModel(PropertyTreeModel * model) { model_ = model; if (model_ && hidden_) { - // process propertyHiddenChanged after insertion into model has finishedAdd commentMore actions - QTimer::singleShot(0, model_, [this]() { - if (model_) { - model_->emitPropertyHiddenChanged(this); + // process propertyHiddenChanged after insertion into model has finished + // Use QPointer to track Property lifetime and avoid use-after-free + QPointer self = this; + QTimer::singleShot(0, model_, [self]() { + if (self && self->model_) { + self->model_->emitPropertyHiddenChanged(self); } }); }