Skip to content

Commit 7531f08

Browse files
azeeymjcarrolladlarkin
committed
Fix segfault at exit (gazebosim#1317)
As discussed in gazebosim#1158, a segfault occurs during exit because Views created as a result of an ECM query by plugins have their destructors stored in the shared library of the plugin. For GUI plugins, the plugins are unloaded from memory before the ECM is destructed, so when it's time to destruct the Views, a segfault occurs because the pointer to the virtual destructor is invalid. This PR is fixes the problem by making View a regular class instead of a template. This ensures that the destructor of View is stored in the core library of ignition-gazebo. As a result, the ECM can be destructed after GUI plugins have been unloaded. Signed-off-by: Addisu Z. Taddese <[email protected]> Co-authored-by: Michael Carroll <[email protected]> Co-authored-by: Ashton Larkin <[email protected]> Signed-off-by: Addisu Z. Taddese <[email protected]>
1 parent b2549dd commit 7531f08

10 files changed

+422
-215
lines changed

include/ignition/gazebo/EntityComponentManager.hh

+1-1
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ namespace ignition
773773
/// \tparam ComponentTypeTs All the component types that define a view.
774774
/// \return A pointer to the view.
775775
private: template<typename ...ComponentTypeTs>
776-
detail::View<ComponentTypeTs...> *FindView() const;
776+
detail::View *FindView() const;
777777

778778
/// \brief Find a view based on the provided component type ids.
779779
/// \param[in] _types The component type ids that serve as a key into

include/ignition/gazebo/detail/BaseView.hh

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#define IGNITION_GAZEBO_DETAIL_BASEVIEW_HH_
1919

2020
#include <cstddef>
21-
#include <memory>
2221
#include <set>
2322
#include <unordered_map>
2423
#include <vector>
@@ -69,7 +68,7 @@ struct ComponentTypeHasher
6968
class IGNITION_GAZEBO_VISIBLE BaseView
7069
{
7170
/// \brief Destructor
72-
public: virtual ~BaseView() = default;
71+
public: virtual ~BaseView();
7372

7473
/// \brief See if an entity is a part of the view
7574
/// \param[in] _entity The entity

include/ignition/gazebo/detail/EntityComponentManager.hh

+59-10
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,50 @@ void EntityComponentManager::EachNoCache(typename identity<std::function<
372372
}
373373
}
374374

375+
namespace detail
376+
{
377+
/// \brief Helper template to call a callback function with each of the
378+
/// components in the _data vector expanded as arguments to the callback
379+
/// function.
380+
/// \tparam ComponentTypeTs The actual types of each of the components.
381+
/// \tparam FuncT The type of the callback function.
382+
/// \tparam BaseComponentT Either "BaseComponent" or "const BaseComponent"
383+
/// \tparam Is Index sequence that will be used to iterate through the vector
384+
/// _data.
385+
/// \param[in] _f The callback function
386+
/// \param[in] _entity The entity associated with the components.
387+
/// \param[in] _data A vector of component pointers that will be expanded to
388+
/// become the arguments of the callback function _f.
389+
/// \return The value of return by the function _f.
390+
template <typename... ComponentTypeTs, typename FuncT, typename BaseComponentT,
391+
std::size_t... Is>
392+
constexpr bool applyFunctionImpl(const FuncT &_f, const Entity &_entity,
393+
const std::vector<BaseComponentT *> &_data,
394+
std::index_sequence<Is...>)
395+
{
396+
return _f(_entity, static_cast<ComponentTypeTs *>(_data[Is])...);
397+
}
398+
399+
/// \brief Helper template to call a callback function with each of the
400+
/// components in the _data vector expanded as arguments to the callback
401+
/// function.
402+
/// \tparam ComponentTypeTs The actual types of each of the components.
403+
/// \tparam FuncT The type of the callback function.
404+
/// \tparam BaseComponentT Either "BaseComponent" or "const BaseComponent"
405+
/// \param[in] _f The callback function
406+
/// \param[in] _entity The entity associated with the components.
407+
/// \param[in] _data A vector of component pointers that will be expanded to
408+
/// become the arguments of the callback function _f.
409+
/// \return The value of return by the function _f.
410+
template <typename... ComponentTypeTs, typename FuncT, typename BaseComponentT>
411+
constexpr bool applyFunction(const FuncT &_f, const Entity &_entity,
412+
const std::vector<BaseComponentT *> &_data)
413+
{
414+
return applyFunctionImpl<ComponentTypeTs...>(
415+
_f, _entity, _data, std::index_sequence_for<ComponentTypeTs...>{});
416+
}
417+
} // namespace detail
418+
375419
//////////////////////////////////////////////////
376420
template<typename ...ComponentTypeTs>
377421
void EntityComponentManager::Each(typename identity<std::function<
@@ -385,7 +429,8 @@ void EntityComponentManager::Each(typename identity<std::function<
385429
// function.
386430
for (const Entity entity : view->Entities())
387431
{
388-
if (!std::apply(_f, view->EntityComponentConstData(entity)))
432+
const auto &data = view->EntityComponentData(entity);
433+
if (!detail::applyFunction<const ComponentTypeTs...>(_f, entity, data))
389434
{
390435
break;
391436
}
@@ -405,7 +450,8 @@ void EntityComponentManager::Each(typename identity<std::function<
405450
// function.
406451
for (const Entity entity : view->Entities())
407452
{
408-
if (!std::apply(_f, view->EntityComponentData(entity)))
453+
const auto &data = view->EntityComponentData(entity);
454+
if (!detail::applyFunction<ComponentTypeTs...>(_f, entity, data))
409455
{
410456
break;
411457
}
@@ -434,7 +480,8 @@ void EntityComponentManager::EachNew(typename identity<std::function<
434480
// function.
435481
for (const Entity entity : view->NewEntities())
436482
{
437-
if (!std::apply(_f, view->EntityComponentData(entity)))
483+
const auto &data = view->EntityComponentData(entity);
484+
if (!detail::applyFunction<ComponentTypeTs...>(_f, entity, data))
438485
{
439486
break;
440487
}
@@ -455,7 +502,8 @@ void EntityComponentManager::EachNew(typename identity<std::function<
455502
// function.
456503
for (const Entity entity : view->NewEntities())
457504
{
458-
if (!std::apply(_f, view->EntityComponentConstData(entity)))
505+
const auto &data = view->EntityComponentData(entity);
506+
if (!detail::applyFunction<const ComponentTypeTs...>(_f, entity, data))
459507
{
460508
break;
461509
}
@@ -476,7 +524,8 @@ void EntityComponentManager::EachRemoved(typename identity<std::function<
476524
// function.
477525
for (const Entity entity : view->ToRemoveEntities())
478526
{
479-
if (!std::apply(_f, view->EntityComponentConstData(entity)))
527+
const auto &data = view->EntityComponentData(entity);
528+
if (!detail::applyFunction<const ComponentTypeTs...>(_f, entity, data))
480529
{
481530
break;
482531
}
@@ -485,15 +534,15 @@ void EntityComponentManager::EachRemoved(typename identity<std::function<
485534

486535
//////////////////////////////////////////////////
487536
template<typename ...ComponentTypeTs>
488-
detail::View<ComponentTypeTs...> *EntityComponentManager::FindView() const
537+
detail::View *EntityComponentManager::FindView() const
489538
{
490539
auto viewKey = std::vector<ComponentTypeId>{ComponentTypeTs::typeId...};
491540

492541
auto baseViewMutexPair = this->FindView(viewKey);
493542
auto baseViewPtr = baseViewMutexPair.first;
494543
if (nullptr != baseViewPtr)
495544
{
496-
auto view = static_cast<detail::View<ComponentTypeTs...>*>(baseViewPtr);
545+
auto view = static_cast<detail::View*>(baseViewPtr);
497546

498547
std::unique_ptr<std::lock_guard<std::mutex>> viewLock;
499548
if (this->LockAddingEntitiesToViews())
@@ -527,7 +576,7 @@ detail::View<ComponentTypeTs...> *EntityComponentManager::FindView() const
527576
}
528577

529578
// create a new view if one wasn't found
530-
detail::View<ComponentTypeTs...> view;
579+
detail::View view(std::set<ComponentTypeId>{ComponentTypeTs::typeId...});
531580

532581
for (const auto &vertex : this->Entities().Vertices())
533582
{
@@ -547,8 +596,8 @@ detail::View<ComponentTypeTs...> *EntityComponentManager::FindView() const
547596
}
548597

549598
baseViewPtr = this->AddView(viewKey,
550-
std::make_unique<detail::View<ComponentTypeTs...>>(view));
551-
return static_cast<detail::View<ComponentTypeTs...>*>(baseViewPtr);
599+
std::make_unique<detail::View>(std::move(view)));
600+
return static_cast<detail::View *>(baseViewPtr);
552601
}
553602

554603
//////////////////////////////////////////////////

0 commit comments

Comments
 (0)