From f649cb3927c014bb628adf0c70d6a1e34401ee87 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Thu, 15 Oct 2026 16:20:41 +0200 Subject: [PATCH 1/2] Fix crash in ~Executor for executors using the minimal constructor Signed-off-by: Alejandro Hernandez Cordero --- rclcpp/src/rclcpp/executor.cpp | 12 ++++++++---- rclcpp/test/rclcpp/test_executor.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/rclcpp/src/rclcpp/executor.cpp b/rclcpp/src/rclcpp/executor.cpp index 15ba78b104..765faf19dd 100644 --- a/rclcpp/src/rclcpp/executor.cpp +++ b/rclcpp/src/rclcpp/executor.cpp @@ -97,8 +97,12 @@ Executor::~Executor() { std::lock_guard guard(mutex_); - notify_waitable_->remove_guard_condition(interrupt_guard_condition_); - notify_waitable_->remove_guard_condition(shutdown_guard_condition_); + // notify_waitable_ is null when a derived executor used the constructor that + // does not initialize the base functionality. + if (notify_waitable_) { + notify_waitable_->remove_guard_condition(interrupt_guard_condition_); + notify_waitable_->remove_guard_condition(shutdown_guard_condition_); + } current_collection_.timers.update( {}, {}, [this](auto timer) {wait_set_.remove_timer(std::move(timer));}); @@ -125,8 +129,8 @@ Executor::~Executor() {}, {}, [this](auto waitable) {wait_set_.remove_waitable(std::move(waitable));}); - // Remove shutdown callback handle registered to Context - if (!context_->remove_on_shutdown_callback(shutdown_callback_handle_)) { + // Remove shutdown callback handle registered to Context, if one was registered + if (notify_waitable_ && !context_->remove_on_shutdown_callback(shutdown_callback_handle_)) { RCUTILS_LOG_ERROR_NAMED( "rclcpp", "failed to remove registered on_shutdown callback"); diff --git a/rclcpp/test/rclcpp/test_executor.cpp b/rclcpp/test/rclcpp/test_executor.cpp index beda7e83ce..5c70d5cf85 100644 --- a/rclcpp/test/rclcpp/test_executor.cpp +++ b/rclcpp/test/rclcpp/test_executor.cpp @@ -27,6 +27,7 @@ #include "rclcpp/callback_group.hpp" #include "rclcpp/client.hpp" +#include "rclcpp/contexts/default_context.hpp" #include "rclcpp/create_subscription.hpp" #include "rclcpp/exceptions.hpp" #include "rclcpp/executor.hpp" @@ -64,6 +65,21 @@ class DummyExecutor : public rclcpp::Executor } }; +// Derived executor that uses the constructor which does not initialize the +// base class functionality. +class MinimalExecutor : public rclcpp::Executor +{ +public: + MinimalExecutor() + : rclcpp::Executor(rclcpp::contexts::get_global_default_context()) + { + } + + void spin() override + { + } +}; + class TestExecutor : public ::testing::Test { public: @@ -117,6 +133,14 @@ TEST_F(TestExecutor, add_remove_node_thread_safe) { future.get(); } +TEST_F(TestExecutor, destroy_executor_without_base_functionality) { + EXPECT_NO_THROW( + { + auto executor = std::make_unique(); + executor.reset(); + }); +} + TEST_F(TestExecutor, constructor_bad_guard_condition_init) { auto mock = mocking_utils::patch_and_return( "lib:rclcpp", rcl_guard_condition_init, RCL_RET_ERROR); From f4def90420a4735348efa7f99b3b871c395f60b2 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Mon, 19 Oct 2026 09:46:24 +0200 Subject: [PATCH 2/2] fix windows build Signed-off-by: Alejandro Hernandez Cordero --- rclcpp/include/rclcpp/executor.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/rclcpp/include/rclcpp/executor.hpp b/rclcpp/include/rclcpp/executor.hpp index 2734b7254b..353ef2ec81 100644 --- a/rclcpp/include/rclcpp/executor.hpp +++ b/rclcpp/include/rclcpp/executor.hpp @@ -414,6 +414,7 @@ class Executor * that explicitly does not want to use the default implementation provided * by this class. */ + RCLCPP_PUBLIC explicit Executor(const std::shared_ptr & context); /// Add a node to executor, execute the next available unit of work, and remove the node.