source/*: Implement heap based userdata

This makes no immediate change to the external interface, but it will
enable us to do things like making copies of the event sources and
support for floating event source types.

Change-Id: Ida73e773eb0869f6f6f21c1e03c61e9ce2b5625c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/sdeventplus/source/base.cpp b/src/sdeventplus/source/base.cpp
index 319b510..bd4a42a 100644
--- a/src/sdeventplus/source/base.cpp
+++ b/src/sdeventplus/source/base.cpp
@@ -2,7 +2,7 @@
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/base.hpp>
-#include <type_traits>
+#include <sdeventplus/types.hpp>
 #include <utility>
 
 namespace sdeventplus
@@ -10,14 +10,6 @@
 namespace source
 {
 
-Base::~Base()
-{
-    if (source)
-    {
-        set_enabled(Enabled::Off);
-    }
-}
-
 sd_event_source* Base::get() const
 {
     return source.value();
@@ -52,20 +44,15 @@
                             &internal::SdEvent::sd_event_source_set_prepare,
                             event.getSdEvent(), get(),
                             callback ? prepareCallback : nullptr);
-        prepare = std::move(callback);
+        get_userdata().prepare = std::move(callback);
     }
     catch (...)
     {
-        prepare = nullptr;
+        get_userdata().prepare = nullptr;
         throw;
     }
 }
 
-Base::Callback& Base::get_prepare()
-{
-    return prepare;
-}
-
 bool Base::get_pending() const
 {
     return internal::callCheck("sd_event_source_get_pending",
@@ -106,41 +93,48 @@
 }
 
 Base::Base(const Event& event, sd_event_source* source, std::false_type) :
-    event(event), source(std::move(source), event.getSdEvent())
+    event(event), source(std::move(source), event.getSdEvent(), true)
 {
-    set_userdata();
 }
 
-Base::Base(Base&& other) :
-    event(std::move(other.event)), source(std::move(other.source)),
-    prepare(std::move(other.prepare))
+Base::Base(const Base& other, sdeventplus::internal::NoOwn) :
+    event(other.get_event(), sdeventplus::internal::NoOwn()),
+    source(other.get(), event.getSdEvent(), false)
 {
-    set_userdata();
 }
 
-Base& Base::operator=(Base&& other)
+void Base::set_userdata(std::unique_ptr<detail::BaseData> data) const
 {
-    if (this != &other)
+    internal::callCheck(
+        "sd_event_source_set_destroy_callback",
+        &internal::SdEvent::sd_event_source_set_destroy_callback,
+        event.getSdEvent(), get(), &Base::destroy_userdata);
+    event.getSdEvent()->sd_event_source_set_userdata(get(), data.release());
+}
+
+detail::BaseData& Base::get_userdata() const
+{
+    return *reinterpret_cast<detail::BaseData*>(
+        event.getSdEvent()->sd_event_source_get_userdata(get()));
+}
+
+Base::Callback& Base::get_prepare()
+{
+    return get_userdata().prepare;
+}
+
+void Base::drop(sd_event_source*&& source, const internal::SdEvent*& sdevent,
+                bool& owned)
+{
+    if (owned)
     {
-        // We need to make sure our current event is not triggered
-        // after it gets deleted in the move
-        if (source)
-        {
-            set_enabled(Enabled::Off);
-        }
-
-        event = std::move(other.event);
-        source = std::move(other.source);
-        prepare = std::move(other.prepare);
-
-        set_userdata();
+        sdevent->sd_event_source_unref(source);
     }
-    return *this;
 }
 
-void Base::drop(sd_event_source*&& source, const internal::SdEvent*& sdevent)
+void Base::destroy_userdata(void* userdata)
 {
-    sdevent->sd_event_source_unref(source);
+    delete static_cast<Base*>(userdata);
 }
 
 int Base::prepareCallback(sd_event_source* source, void* userdata)
@@ -149,10 +143,15 @@
                                                               source, userdata);
 }
 
-void Base::set_userdata()
+namespace detail
 {
-    event.getSdEvent()->sd_event_source_set_userdata(get(), this);
+
+BaseData::BaseData(const Base& base) :
+    Base(base, sdeventplus::internal::NoOwn())
+{
 }
 
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/base.hpp b/src/sdeventplus/source/base.hpp
index d177079..4c3ed79 100644
--- a/src/sdeventplus/source/base.hpp
+++ b/src/sdeventplus/source/base.hpp
@@ -5,8 +5,10 @@
 #include <cstdio>
 #include <function2/function2.hpp>
 #include <functional>
+#include <memory>
 #include <sdeventplus/event.hpp>
 #include <sdeventplus/internal/utils.hpp>
+#include <sdeventplus/types.hpp>
 #include <stdplus/handle/managed.hpp>
 #include <systemd/sd-bus.h>
 #include <type_traits>
@@ -28,6 +30,11 @@
     OneShot = SD_EVENT_ONESHOT,
 };
 
+namespace detail
+{
+class BaseData;
+} // namespace detail
+
 /** @class Base
  *  @brief The base class for all sources implementing common source methods
  *         Not instantiated directly by end users
@@ -37,7 +44,9 @@
   public:
     using Callback = fu2::unique_function<void(Base& source)>;
 
-    virtual ~Base();
+    Base(Base&& other) = default;
+    Base& operator=(Base&& other) = default;
+    virtual ~Base() = default;
 
     /** @brief Gets the underlying sd_event_source
      *
@@ -123,17 +132,33 @@
      *  @param[in] event  - The event associated with the source
      *  @param[in] source - The underlying sd_event_source wrapped
      *  @param[in]        - Signifies that ownership is being transfered
-     *  @throws SdEventError for underlying sd_event errors
      */
     Base(const Event& event, sd_event_source* source, std::false_type);
 
-    // We can't ever copy an event_source because the callback
-    // data has to be unique.
-    Base(const Base& other) = delete;
-    Base& operator=(const Base& other) = delete;
-    // We don't want to allow any kind of slicing.
-    Base(Base&& other);
-    Base& operator=(Base&& other);
+    /** @brief Constructs a basic non-owning event source wrapper
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     */
+    Base(const Base& other, sdeventplus::internal::NoOwn);
+
+    /** @brief Sets the userdata of the source to the passed in source
+     *         This needs to be called by all source implementors.
+     *
+     *  @param[in] data - The data stored in the userdata slot.
+     *  @throws SdEventError for underlying sd_event errors
+     */
+    void set_userdata(std::unique_ptr<detail::BaseData> data) const;
+
+    /** @brief Get the heap allocated version of the Base
+     *
+     *  @return A reference to the Base
+     */
+    detail::BaseData& get_userdata() const;
 
     /** @brief Returns a reference to the prepare callback executed for this
      *         source
@@ -152,8 +177,7 @@
      *  @param[in] args...  - Extra arguments to pass to the callaback
      *  @return An negative errno on error, or 0 on success
      */
-    template <typename Callback, class Source, Callback& (Source::*getter)(),
-              typename... Args>
+    template <typename Callback, class Data, auto getter, typename... Args>
     static int sourceCallback(const char* name, sd_event_source*,
                               void* userdata, Args&&... args)
     {
@@ -162,26 +186,27 @@
             fprintf(stderr, "sdeventplus: %s: Missing userdata\n", name);
             return -EINVAL;
         }
-        Source* source = reinterpret_cast<Source*>(userdata);
-        return internal::performCallback(name, (source->*getter)(),
-                                         std::ref(*source),
+        Data& data =
+            static_cast<Data&>(*reinterpret_cast<detail::BaseData*>(userdata));
+        Callback& callback = std::invoke(getter, data);
+        return internal::performCallback(name, callback, std::ref(data),
                                          std::forward<Args>(args)...);
     }
 
   private:
     static void drop(sd_event_source*&& source,
-                     const internal::SdEvent*& sdevent);
+                     const internal::SdEvent*& sdevent, bool& owned);
 
-    stdplus::Managed<sd_event_source*, const internal::SdEvent*>::Handle<drop>
+    stdplus::Managed<sd_event_source*, const internal::SdEvent*,
+                     bool>::Handle<drop>
         source;
-    Callback prepare;
 
-    /** @brief A helper used to make sure the userdata for the sd-event
-     *         callback is set to the current source c++ object
+    /** @brief A wrapper around deleting the heap allocated base class
+     *         This is needed for calls from sd_event destroy callbacks.
      *
-     *  @throws SdEventError for underlying sd_event errors
+     * @param[in] userdata - The provided userdata for the source
      */
-    void set_userdata();
+    static void destroy_userdata(void* userdata);
 
     /** @brief A wrapper around the callback that can be called from sd-event
      *
@@ -192,5 +217,21 @@
     static int prepareCallback(sd_event_source* source, void* userdata);
 };
 
+namespace detail
+{
+
+class BaseData : public Base
+{
+  private:
+    Base::Callback prepare;
+
+  public:
+    BaseData(const Base& base);
+
+    friend Base;
+};
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/child.cpp b/src/sdeventplus/source/child.cpp
index 9701d82..925a223 100644
--- a/src/sdeventplus/source/child.cpp
+++ b/src/sdeventplus/source/child.cpp
@@ -1,6 +1,8 @@
+#include <memory>
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/child.hpp>
+#include <sdeventplus/types.hpp>
 #include <type_traits>
 #include <utility>
 
@@ -10,14 +12,20 @@
 {
 
 Child::Child(const Event& event, pid_t pid, int options, Callback&& callback) :
-    Base(event, create_source(event, pid, options), std::false_type()),
-    callback(std::move(callback))
+    Base(event, create_source(event, pid, options), std::false_type())
+{
+    set_userdata(
+        std::make_unique<detail::ChildData>(*this, std::move(callback)));
+}
+
+Child::Child(const Child& other, sdeventplus::internal::NoOwn) :
+    Base(other, sdeventplus::internal::NoOwn())
 {
 }
 
 void Child::set_callback(Callback&& callback)
 {
-    this->callback = std::move(callback);
+    get_userdata().callback = std::move(callback);
 }
 
 pid_t Child::get_pid() const
@@ -29,9 +37,14 @@
     return pid;
 }
 
+detail::ChildData& Child::get_userdata() const
+{
+    return static_cast<detail::ChildData&>(Base::get_userdata());
+}
+
 Child::Callback& Child::get_callback()
 {
-    return callback;
+    return get_userdata().callback;
 }
 
 sd_event_source* Child::create_source(const Event& event, pid_t pid,
@@ -48,9 +61,20 @@
 int Child::childCallback(sd_event_source* source, const siginfo_t* si,
                          void* userdata)
 {
-    return sourceCallback<Callback, Child, &Child::get_callback>(
+    return sourceCallback<Callback, detail::ChildData, &Child::get_callback>(
         "childCallback", source, userdata, si);
 }
 
+namespace detail
+{
+
+ChildData::ChildData(const Child& base, Child::Callback&& callback) :
+    Child(base, sdeventplus::internal::NoOwn()), BaseData(base),
+    callback(std::move(callback))
+{
+}
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/child.hpp b/src/sdeventplus/source/child.hpp
index 4f29994..7022a3c 100644
--- a/src/sdeventplus/source/child.hpp
+++ b/src/sdeventplus/source/child.hpp
@@ -2,6 +2,7 @@
 
 #include <function2/function2.hpp>
 #include <sdeventplus/source/base.hpp>
+#include <sdeventplus/types.hpp>
 #include <signal.h>
 
 namespace sdeventplus
@@ -9,6 +10,11 @@
 namespace source
 {
 
+namespace detail
+{
+class ChildData;
+} // namespace detail
+
 /** @class Child
  *  @brief A wrapper around the sd_event_source child type
  *         See sd_event_add_child(3) for more information
@@ -28,10 +34,20 @@
      *  @param[in] options  - An OR-ed mask that determines triggers
      *                        See waitid(2) for further information
      *  @param[in] callback - The function executed on event dispatch
-     *  @throws SdEventError for underlying sd_event errors
      */
     Child(const Event& event, pid_t pid, int options, Callback&& callback);
 
+    /** @brief Constructs a non-owning child source handler
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     */
+    Child(const Child& other, sdeventplus::internal::NoOwn);
+
     /** @brief Sets the callback
      *
      *  @param[in] callback - The function executed on event dispatch
@@ -46,7 +62,11 @@
     pid_t get_pid() const;
 
   private:
-    Callback callback;
+    /** @brief Returns a reference to the source owned child
+     *
+     *  @return A reference to the child
+     */
+    detail::ChildData& get_userdata() const;
 
     /** @brief Returns a reference to the callback executed for this source
      *
@@ -75,5 +95,21 @@
                              void* userdata);
 };
 
+namespace detail
+{
+
+class ChildData : public Child, public BaseData
+{
+  private:
+    Child::Callback callback;
+
+  public:
+    ChildData(const Child& base, Child::Callback&& callback);
+
+    friend Child;
+};
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/event.cpp b/src/sdeventplus/source/event.cpp
index b65322d..eced2ef 100644
--- a/src/sdeventplus/source/event.cpp
+++ b/src/sdeventplus/source/event.cpp
@@ -1,6 +1,8 @@
+#include <memory>
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/event.hpp>
+#include <sdeventplus/types.hpp>
 #include <utility>
 
 namespace sdeventplus
@@ -10,19 +12,30 @@
 
 void EventBase::set_callback(Callback&& callback)
 {
-    this->callback = std::move(callback);
+    get_userdata().callback = std::move(callback);
+}
+
+EventBase::EventBase(const EventBase& other, sdeventplus::internal::NoOwn) :
+    Base(other, sdeventplus::internal::NoOwn())
+{
 }
 
 EventBase::EventBase(const char* name, CreateFunc create, const Event& event,
                      Callback&& callback) :
-    Base(event, create_source(name, create, event), std::false_type()),
-    callback(std::move(callback))
+    Base(event, create_source(name, create, event), std::false_type())
 {
+    set_userdata(
+        std::make_unique<detail::EventBaseData>(*this, std::move(callback)));
+}
+
+detail::EventBaseData& EventBase::get_userdata() const
+{
+    return static_cast<detail::EventBaseData&>(Base::get_userdata());
 }
 
 EventBase::Callback& EventBase::get_callback()
 {
-    return callback;
+    return get_userdata().callback;
 }
 
 sd_event_source* EventBase::create_source(const char* name, CreateFunc create,
@@ -36,10 +49,23 @@
 
 int EventBase::eventCallback(sd_event_source* source, void* userdata)
 {
-    return sourceCallback<Callback, EventBase, &EventBase::get_callback>(
-        "eventCallback", source, userdata);
+    return sourceCallback<Callback, detail::EventBaseData,
+                          &EventBase::get_callback>("eventCallback", source,
+                                                    userdata);
 }
 
+namespace detail
+{
+
+EventBaseData::EventBaseData(const EventBase& base,
+                             EventBase::Callback&& callback) :
+    EventBase(base, sdeventplus::internal::NoOwn()),
+    BaseData(base), callback(std::move(callback))
+{
+}
+
+} // namespace detail
+
 Defer::Defer(const Event& event, Callback&& callback) :
     EventBase("sd_event_add_defer", &internal::SdEvent::sd_event_add_defer,
               event, std::move(callback))
diff --git a/src/sdeventplus/source/event.hpp b/src/sdeventplus/source/event.hpp
index a2ee939..60b1252 100644
--- a/src/sdeventplus/source/event.hpp
+++ b/src/sdeventplus/source/event.hpp
@@ -3,13 +3,20 @@
 #include <function2/function2.hpp>
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/source/base.hpp>
+#include <sdeventplus/types.hpp>
 #include <systemd/sd-event.h>
+#include <type_traits>
 
 namespace sdeventplus
 {
 namespace source
 {
 
+namespace detail
+{
+class EventBaseData;
+} // namespace detail
+
 /** @class EventBase
  *  @brief A wrapper around the sd_event_source defer type
  *         See sd_event_add_defer(3) for more information
@@ -27,6 +34,17 @@
      */
     void set_callback(Callback&& callback);
 
+    /** @brief Constructs a non-owning event source handler
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     */
+    EventBase(const EventBase& other, sdeventplus::internal::NoOwn);
+
   protected:
     using CreateFunc = decltype(&internal::SdEvent::sd_event_add_exit);
 
@@ -38,13 +56,16 @@
      *  @param[in] create - The SdEvent function called to create the source
      *  @param[in] event  - The event to attach the handler
      *  @param[in] callback - The function executed on event dispatch
-     *  @throws SdEventError for underlying sd_event errors
      */
     EventBase(const char* name, CreateFunc create, const Event& event,
               Callback&& callback);
 
   private:
-    Callback callback;
+    /** @brief Returns a reference to the source owned event
+     *
+     *  @return A reference to the event
+     */
+    detail::EventBaseData& get_userdata() const;
 
     /** @brief Returns a reference to the callback executed for this source
      *
@@ -72,6 +93,22 @@
     static int eventCallback(sd_event_source* source, void* userdata);
 };
 
+namespace detail
+{
+
+class EventBaseData : public EventBase, public BaseData
+{
+  private:
+    EventBase::Callback callback;
+
+  public:
+    EventBaseData(const EventBase& base, EventBase::Callback&& callback);
+
+    friend EventBase;
+};
+
+} // namespace detail
+
 class Defer : public EventBase
 {
   public:
diff --git a/src/sdeventplus/source/io.cpp b/src/sdeventplus/source/io.cpp
index 9bd4005..3bafd9a 100644
--- a/src/sdeventplus/source/io.cpp
+++ b/src/sdeventplus/source/io.cpp
@@ -1,6 +1,7 @@
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/io.hpp>
+#include <sdeventplus/types.hpp>
 #include <type_traits>
 #include <utility>
 
@@ -10,14 +11,19 @@
 {
 
 IO::IO(const Event& event, int fd, uint32_t events, Callback&& callback) :
-    Base(event, create_source(event, fd, events), std::false_type()),
-    callback(std::move(callback))
+    Base(event, create_source(event, fd, events), std::false_type())
+{
+    set_userdata(std::make_unique<detail::IOData>(*this, std::move(callback)));
+}
+
+IO::IO(const IO& other, sdeventplus::internal::NoOwn) :
+    Base(other, sdeventplus::internal::NoOwn())
 {
 }
 
 void IO::set_callback(Callback&& callback)
 {
-    this->callback = std::move(callback);
+    get_userdata().callback = std::move(callback);
 }
 
 int IO::get_fd() const
@@ -59,9 +65,14 @@
     return revents;
 }
 
+detail::IOData& IO::get_userdata() const
+{
+    return static_cast<detail::IOData&>(Base::get_userdata());
+}
+
 IO::Callback& IO::get_callback()
 {
-    return callback;
+    return get_userdata().callback;
 }
 
 sd_event_source* IO::create_source(const Event& event, int fd, uint32_t events)
@@ -76,9 +87,20 @@
 int IO::ioCallback(sd_event_source* source, int fd, uint32_t revents,
                    void* userdata)
 {
-    return sourceCallback<Callback, IO, &IO::get_callback>(
+    return sourceCallback<Callback, detail::IOData, &IO::get_callback>(
         "ioCallback", source, userdata, fd, revents);
 }
 
+namespace detail
+{
+
+IOData::IOData(const IO& base, IO::Callback&& callback) :
+    IO(base, sdeventplus::internal::NoOwn()), BaseData(base),
+    callback(std::move(callback))
+{
+}
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/io.hpp b/src/sdeventplus/source/io.hpp
index 409a1fe..ebb9e34 100644
--- a/src/sdeventplus/source/io.hpp
+++ b/src/sdeventplus/source/io.hpp
@@ -4,12 +4,18 @@
 #include <function2/function2.hpp>
 #include <sdeventplus/source/base.hpp>
 #include <systemd/sd-event.h>
+#include <type_traits>
 
 namespace sdeventplus
 {
 namespace source
 {
 
+namespace detail
+{
+class IOData;
+} // namespace detail
+
 /** @class IO
  *  @brief A wrapper around the sd_event_source IO type
  *         See sd_event_add_io(3) for more information
@@ -28,10 +34,20 @@
      *  @param[in] events   - The event mask passed which determines triggers
      *                        See epoll_ctl(2) for more info on the mask
      *  @param[in] callback - The function executed on event dispatch
-     *  @throws SdEventError for underlying sd_event errors
      */
     IO(const Event& event, int fd, uint32_t events, Callback&& callback);
 
+    /** @brief Constructs a non-owning io source handler
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     */
+    IO(const IO& event, sdeventplus::internal::NoOwn);
+
     /** @brief Sets the callback
      *
      *  @param[in] callback - The function executed on event dispatch
@@ -77,7 +93,11 @@
     uint32_t get_revents() const;
 
   private:
-    Callback callback;
+    /** @brief Returns a reference to the source owned io
+     *
+     *  @return A reference to the io
+     */
+    detail::IOData& get_userdata() const;
 
     /** @brief Returns a reference to the callback executed for this source
      *
@@ -107,5 +127,21 @@
                           void* userdata);
 };
 
+namespace detail
+{
+
+class IOData : public IO, public BaseData
+{
+  private:
+    IO::Callback callback;
+
+  public:
+    IOData(const IO& base, IO::Callback&& callback);
+
+    friend IO;
+};
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/signal.cpp b/src/sdeventplus/source/signal.cpp
index a433cb4..97ae171 100644
--- a/src/sdeventplus/source/signal.cpp
+++ b/src/sdeventplus/source/signal.cpp
@@ -1,6 +1,8 @@
+#include <memory>
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/signal.hpp>
+#include <sdeventplus/types.hpp>
 #include <type_traits>
 #include <utility>
 
@@ -10,14 +12,20 @@
 {
 
 Signal::Signal(const Event& event, int sig, Callback&& callback) :
-    Base(event, create_source(event, sig), std::false_type()),
-    callback(std::move(callback))
+    Base(event, create_source(event, sig), std::false_type())
+{
+    set_userdata(
+        std::make_unique<detail::SignalData>(*this, std::move(callback)));
+}
+
+Signal::Signal(const Signal& other, sdeventplus::internal::NoOwn) :
+    Base(other, sdeventplus::internal::NoOwn())
 {
 }
 
 void Signal::set_callback(Callback&& callback)
 {
-    this->callback = std::move(callback);
+    get_userdata().callback = std::move(callback);
 }
 
 int Signal::get_signal() const
@@ -27,9 +35,14 @@
                                event.getSdEvent(), get());
 }
 
+detail::SignalData& Signal::get_userdata() const
+{
+    return static_cast<detail::SignalData&>(Base::get_userdata());
+}
+
 Signal::Callback& Signal::get_callback()
 {
-    return callback;
+    return get_userdata().callback;
 }
 
 sd_event_source* Signal::create_source(const Event& event, int sig)
@@ -44,9 +57,20 @@
 int Signal::signalCallback(sd_event_source* source,
                            const struct signalfd_siginfo* si, void* userdata)
 {
-    return sourceCallback<Callback, Signal, &Signal::get_callback>(
+    return sourceCallback<Callback, detail::SignalData, &Signal::get_callback>(
         "signalCallback", source, userdata, si);
 }
 
+namespace detail
+{
+
+SignalData::SignalData(const Signal& base, Signal::Callback&& callback) :
+    Signal(base, sdeventplus::internal::NoOwn()), BaseData(base),
+    callback(std::move(callback))
+{
+}
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/signal.hpp b/src/sdeventplus/source/signal.hpp
index 08c0eff..d5035d1 100644
--- a/src/sdeventplus/source/signal.hpp
+++ b/src/sdeventplus/source/signal.hpp
@@ -3,6 +3,7 @@
 #include <function2/function2.hpp>
 #include <sdeventplus/event.hpp>
 #include <sdeventplus/source/base.hpp>
+#include <sdeventplus/types.hpp>
 #include <sys/signalfd.h>
 
 namespace sdeventplus
@@ -10,6 +11,11 @@
 namespace source
 {
 
+namespace detail
+{
+class SignalData;
+} // namespace detail
+
 /** @class Signal
  *  @brief A wrapper around the sd_event_source signal type
  *         See sd_event_add_signal(3) for more information
@@ -33,6 +39,18 @@
      */
     Signal(const Event& event, int sig, Callback&& callback);
 
+    /** @brief Constructs a non-owning signal source handler
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     *  @throws SdEventError for underlying sd_event errors
+     */
+    Signal(const Signal& other, sdeventplus::internal::NoOwn);
+
     /** @brief Sets the callback
      *
      *  @param[in] callback - The function executed on event dispatch
@@ -47,7 +65,11 @@
     int get_signal() const;
 
   private:
-    Callback callback;
+    /** @brief Returns a reference to the source owned signal
+     *
+     *  @return A reference to the signal
+     */
+    detail::SignalData& get_userdata() const;
 
     /** @brief Returns a reference to the callback executed for this source
      *
@@ -76,5 +98,21 @@
                               void* userdata);
 };
 
+namespace detail
+{
+
+class SignalData : public Signal, public BaseData
+{
+  private:
+    Signal::Callback callback;
+
+  public:
+    SignalData(const Signal& base, Signal::Callback&& callback);
+
+    friend Signal;
+};
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/time.cpp b/src/sdeventplus/source/time.cpp
index 0b62f29..03c4665 100644
--- a/src/sdeventplus/source/time.cpp
+++ b/src/sdeventplus/source/time.cpp
@@ -1,8 +1,9 @@
-#include <cstdio>
+#include <memory>
 #include <sdeventplus/clock.hpp>
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/time.hpp>
+#include <sdeventplus/types.hpp>
 #include <type_traits>
 #include <utility>
 
@@ -14,15 +15,22 @@
 template <ClockId Id>
 Time<Id>::Time(const Event& event, TimePoint time, Accuracy accuracy,
                Callback&& callback) :
-    Base(event, create_source(event, time, accuracy), std::false_type()),
-    callback(std::move(callback))
+    Base(event, create_source(event, time, accuracy), std::false_type())
+{
+    set_userdata(
+        std::make_unique<detail::TimeData<Id>>(*this, std::move(callback)));
+}
+
+template <ClockId Id>
+Time<Id>::Time(const Time<Id>& other, sdeventplus::internal::NoOwn) :
+    Base(other, sdeventplus::internal::NoOwn())
 {
 }
 
 template <ClockId Id>
 void Time<Id>::set_callback(Callback&& callback)
 {
-    this->callback = std::move(callback);
+    get_userdata().callback = std::move(callback);
 }
 
 template <ClockId Id>
@@ -64,9 +72,15 @@
 }
 
 template <ClockId Id>
+detail::TimeData<Id>& Time<Id>::get_userdata() const
+{
+    return static_cast<detail::TimeData<Id>&>(Base::get_userdata());
+}
+
+template <ClockId Id>
 typename Time<Id>::Callback& Time<Id>::get_callback()
 {
-    return callback;
+    return get_userdata().callback;
 }
 
 template <ClockId Id>
@@ -86,7 +100,7 @@
 int Time<Id>::timeCallback(sd_event_source* source, uint64_t usec,
                            void* userdata)
 {
-    return sourceCallback<Callback, Time, &Time::get_callback>(
+    return sourceCallback<Callback, detail::TimeData<Id>, &Time::get_callback>(
         "timeCallback", source, userdata, TimePoint(SdEventDuration(usec)));
 }
 
@@ -96,5 +110,18 @@
 template class Time<ClockId::RealTimeAlarm>;
 template class Time<ClockId::BootTimeAlarm>;
 
+namespace detail
+{
+
+template <ClockId Id>
+TimeData<Id>::TimeData(const Time<Id>& base,
+                       typename Time<Id>::Callback&& callback) :
+    Time<Id>(base, sdeventplus::internal::NoOwn()),
+    BaseData(base), callback(std::move(callback))
+{
+}
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/source/time.hpp b/src/sdeventplus/source/time.hpp
index a262588..f7670b5 100644
--- a/src/sdeventplus/source/time.hpp
+++ b/src/sdeventplus/source/time.hpp
@@ -5,6 +5,7 @@
 #include <sdeventplus/clock.hpp>
 #include <sdeventplus/internal/utils.hpp>
 #include <sdeventplus/source/base.hpp>
+#include <sdeventplus/types.hpp>
 #include <systemd/sd-event.h>
 
 namespace sdeventplus
@@ -12,6 +13,12 @@
 namespace source
 {
 
+namespace detail
+{
+template <ClockId Id>
+class TimeData;
+} // namespace detail
+
 /** @class Time<ClockId>
  *  @brief A wrapper around the sd_event_source time type
  *         See sd_event_add_time(3) for more information
@@ -40,6 +47,18 @@
     Time(const Event& event, TimePoint time, Accuracy accuracy,
          Callback&& callback);
 
+    /** @brief Constructs a non-owning time source handler
+     *         Does not own the passed reference to the source because
+     *         this is meant to be used only as a reference inside an event
+     *         source.
+     *  @internal
+     *
+     *  @param[in] other - The source wrapper to copy
+     *  @param[in]       - Signifies that this new copy is non-owning
+     *  @throws SdEventError for underlying sd_event errors
+     */
+    Time(const Time& other, sdeventplus::internal::NoOwn);
+
     /** @brief Sets the callback
      *
      *  @param[in] callback - The function executed on event dispatch
@@ -75,7 +94,11 @@
     void set_accuracy(Accuracy accuracy) const;
 
   private:
-    Callback callback;
+    /** @brief Returns a reference to the source owned time
+     *
+     *  @return A reference to the time
+     */
+    detail::TimeData<Id>& get_userdata() const;
 
     /** @brief Returns a reference to the callback executed for this source
      *
@@ -104,5 +127,22 @@
                             void* userdata);
 };
 
+namespace detail
+{
+
+template <ClockId Id>
+class TimeData : public Time<Id>, public BaseData
+{
+  private:
+    typename Time<Id>::Callback callback;
+
+  public:
+    TimeData(const Time<Id>& base, typename Time<Id>::Callback&& callback);
+
+    friend Time<Id>;
+};
+
+} // namespace detail
+
 } // namespace source
 } // namespace sdeventplus
diff --git a/src/sdeventplus/utility/timer.cpp b/src/sdeventplus/utility/timer.cpp
index 638f8e1..d078b06 100644
--- a/src/sdeventplus/utility/timer.cpp
+++ b/src/sdeventplus/utility/timer.cpp
@@ -26,6 +26,15 @@
 {
     if (this != &other)
     {
+        try
+        {
+            timeSource.set_enabled(source::Enabled::Off);
+        }
+        catch (std::bad_optional_access&)
+        {
+            // This is normal for a moved object
+        }
+
         expired = std::move(other.expired);
         initialized = std::move(other.initialized);
         callback = std::move(other.callback);
@@ -55,6 +64,19 @@
 }
 
 template <ClockId Id>
+Timer<Id>::~Timer()
+{
+    try
+    {
+        timeSource.set_enabled(source::Enabled::Off);
+    }
+    catch (std::bad_optional_access&)
+    {
+        // This is normal for a moved object
+    }
+}
+
+template <ClockId Id>
 void Timer<Id>::set_callback(Callback&& callback)
 {
     this->callback = std::move(callback);
diff --git a/src/sdeventplus/utility/timer.hpp b/src/sdeventplus/utility/timer.hpp
index bca5566..1453dbe 100644
--- a/src/sdeventplus/utility/timer.hpp
+++ b/src/sdeventplus/utility/timer.hpp
@@ -41,7 +41,7 @@
     Timer(Timer&& other);
     Timer& operator=(const Timer& other) = delete;
     Timer& operator=(Timer&& other);
-    virtual ~Timer() = default;
+    virtual ~Timer();
 
     /** @brief Creates a new timer on the given event loop.
      *         This timer is created enabled by default if passed an interval.
diff --git a/test/source/base.cpp b/test/source/base.cpp
index 27e5bc3..3673e24 100644
--- a/test/source/base.cpp
+++ b/test/source/base.cpp
@@ -1,4 +1,5 @@
 #include <cerrno>
+#include <functional>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <memory>
@@ -8,8 +9,10 @@
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/source/base.hpp>
 #include <sdeventplus/test/sdevent.hpp>
+#include <sdeventplus/types.hpp>
 #include <string>
 #include <systemd/sd-event.h>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -27,24 +30,48 @@
 
 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>;
 
+class BaseImplData;
+
 class BaseImpl : public Base
 {
   public:
-    BaseImpl(const Event& event, sd_event_source* source, std::false_type) :
-        Base(event, source, std::false_type())
+    BaseImpl(const Event& event, sd_event_source* source, std::false_type);
+
+    BaseImpl(const BaseImpl& other, sdeventplus::internal::NoOwn) :
+        Base(other, sdeventplus::internal::NoOwn())
     {
     }
 
     using Base::get_prepare;
 };
 
+class BaseImplData : public BaseImpl, public detail::BaseData
+{
+  public:
+    BaseImplData(const BaseImpl& base) :
+        BaseImpl(base, sdeventplus::internal::NoOwn()), BaseData(base)
+    {
+    }
+};
+
+BaseImpl::BaseImpl(const Event& event, sd_event_source* source,
+                   std::false_type) :
+    Base(event, source, std::false_type())
+{
+    set_userdata(std::make_unique<BaseImplData>(*this));
+}
+
 class BaseTest : public testing::Test
 {
   protected:
     testing::StrictMock<test::SdEventMock> mock;
     sd_event_source* const expected_source =
         reinterpret_cast<sd_event_source*>(1234);
+    sd_event_source* const expected_source2 =
+        reinterpret_cast<sd_event_source*>(3456);
     sd_event* const expected_event = reinterpret_cast<sd_event*>(2345);
+    sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
+
     UniqueEvent event = make_event(expected_event);
 
     UniqueEvent make_event(sd_event* event)
@@ -59,21 +86,30 @@
 
     // Using a unique_ptr to make sure we don't get any superfluous moves or
     // copies.
-    std::unique_ptr<BaseImpl> make_base(const Event& event,
-                                        sd_event_source* source)
+    std::tuple<std::unique_ptr<BaseImpl>, std::function<void()>>
+        make_base(const Event& event, sd_event_source* source)
     {
         EXPECT_CALL(mock, sd_event_ref(event.get()))
             .WillOnce(Return(event.get()));
+        sd_event_destroy_t destroy;
         void* userdata;
-        EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(
+                mock, sd_event_source_set_destroy_callback(source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        }
         auto ret = std::make_unique<BaseImpl>(event, source, std::false_type());
-        EXPECT_EQ(ret.get(), userdata);
+        EXPECT_CALL(mock, sd_event_source_get_userdata(source))
+            .WillRepeatedly(Return(userdata));
+        EXPECT_NE(ret.get(), userdata);
         EXPECT_EQ(source, ret->get());
         EXPECT_NE(&event, &ret->get_event());
         EXPECT_EQ(event.get(), ret->get_event().get());
         EXPECT_FALSE(ret->get_prepare());
-        return ret;
+        return {std::move(ret), std::bind(destroy, userdata)};
     }
 
     void set_prepare_placeholder(BaseImpl& base)
@@ -86,152 +122,107 @@
 
     void empty_base(BaseImpl&& other)
     {
-        void* userdata;
-        EXPECT_CALL(mock, sd_event_source_set_userdata(other.get(), testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
         BaseImpl mover(std::move(other));
-        EXPECT_EQ(&mover, userdata);
         EXPECT_THROW(other.get(), std::bad_optional_access);
         EXPECT_THROW(other.get_event().get(), std::bad_optional_access);
-        EXPECT_FALSE(other.get_prepare());
+        EXPECT_THROW(other.get_prepare(), std::bad_optional_access);
 
         expect_base_destruct(mover.get_event(), mover.get());
     }
 
     void expect_base_destruct(const Event& event, sd_event_source* source)
     {
-        {
-            testing::InSequence seq;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(event.get()))
             .WillOnce(Return(nullptr));
     }
 };
 
+TEST_F(BaseTest, NewBaseFail)
+{
+    EXPECT_CALL(mock, sd_event_ref(expected_event))
+        .WillOnce(Return(expected_event));
+    EXPECT_CALL(
+        mock, sd_event_source_set_destroy_callback(expected_source, testing::_))
+        .WillOnce(Return(-EINVAL));
+    expect_base_destruct(*event, expected_source);
+    EXPECT_THROW(BaseImpl(*event, expected_source, std::false_type()),
+                 SdEventError);
+}
+
 TEST_F(BaseTest, NewBaseNoRef)
 {
     EXPECT_CALL(mock, sd_event_ref(expected_event))
         .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    }
     BaseImpl source(*event, expected_source, std::false_type());
-    EXPECT_EQ(&source, userdata);
+    EXPECT_NE(&source, userdata);
     EXPECT_EQ(expected_source, source.get());
     EXPECT_NE(event.get(), &source.get_event());
     EXPECT_EQ(expected_event, source.get_event().get());
+
+    EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+        .WillOnce(Return(userdata));
     EXPECT_FALSE(source.get_prepare());
 
     expect_base_destruct(*event, expected_source);
+    destroy(userdata);
 }
 
-TEST_F(BaseTest, MoveConstruct)
+TEST_F(BaseTest, UserdataOutlives)
 {
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
+    EXPECT_CALL(mock, sd_event_ref(expected_event))
+        .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-    BaseImpl source2(std::move(*source1));
-    EXPECT_EQ(&source2, userdata);
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2.get());
-    EXPECT_EQ(expected_event, source2.get_event().get());
-    EXPECT_TRUE(source2.get_prepare());
-
-    expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignSelf)
-{
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    *source1 = std::move(*source1);
-    EXPECT_EQ(expected_source, source1->get());
-    EXPECT_EQ(expected_event, source1->get_event().get());
-    EXPECT_TRUE(source1->get_prepare());
-
-    expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignEmpty)
-{
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    std::unique_ptr<BaseImpl> source2 = make_base(*event, expected_source);
-    empty_base(std::move(*source2));
-
     {
-        void* userdata;
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
         EXPECT_CALL(mock,
                     sd_event_source_set_userdata(expected_source, testing::_))
             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-        *source2 = std::move(*source1);
-        EXPECT_EQ(source2.get(), userdata);
     }
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2->get());
-    EXPECT_EQ(expected_event, source2->get_event().get());
-    EXPECT_TRUE(source2->get_prepare());
+    auto source =
+        std::make_unique<BaseImpl>(*event, expected_source, std::false_type());
+    EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+        .WillRepeatedly(Return(userdata));
+    EXPECT_FALSE(source->get_prepare());
 
-    // Make sure source1 is deleted to ensure it isn't holding a reference
-    source1.reset();
     expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignExisting)
-{
-    sd_event_source* const expected_source2 =
-        reinterpret_cast<sd_event_source*>(3456);
-    sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
-
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    UniqueEvent event2 = make_event(expected_event2);
-    std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2);
-
-    {
-        expect_base_destruct(*event2, expected_source2);
-        void* userdata;
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-        *source2 = std::move(*source1);
-        EXPECT_EQ(source2.get(), userdata);
-    }
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2->get());
-    EXPECT_EQ(expected_event, source2->get_event().get());
-    EXPECT_TRUE(source2->get_prepare());
-
-    // Make sure source1 is deleted to ensure it isn't holding a reference
-    source1.reset();
-    expect_base_destruct(*event, expected_source);
+    source.reset();
+    EXPECT_FALSE(reinterpret_cast<BaseImpl*>(userdata)->get_prepare());
+    destroy(userdata);
 }
 
 class BaseMethodTest : public BaseTest
 {
   protected:
-    std::unique_ptr<BaseImpl> base = make_base(*event, expected_source);
+    std::unique_ptr<BaseImpl> base;
+    std::function<void()> destroy;
+
+    void SetUp()
+    {
+        std::tie(base, destroy) = make_base(*event, expected_source);
+    }
 
     void TearDown()
     {
         expect_base_destruct(base->get_event(), base->get());
         base.reset();
+        destroy();
     }
 };
 
diff --git a/test/source/child.cpp b/test/source/child.cpp
index ab173b1..5dc06b9 100644
--- a/test/source/child.cpp
+++ b/test/source/child.cpp
@@ -21,6 +21,7 @@
 
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 
@@ -47,14 +48,8 @@
 
     void expect_destruct()
     {
-        {
-            testing::InSequence sequence;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source,
-                                                          SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(expected_source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(expected_source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(expected_event))
             .WillOnce(Return(nullptr));
     }
@@ -72,9 +67,19 @@
                                          options, testing::_, nullptr))
         .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&handler),
                         Return(0)));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     int completions = 0;
     const siginfo_t* return_si;
     Child::Callback callback = [&](Child&, const siginfo_t* si) {
@@ -83,19 +88,20 @@
     };
     Child child(*event, pid, options, std::move(callback));
     EXPECT_FALSE(callback);
-    EXPECT_EQ(&child, userdata);
+    EXPECT_NE(&child, userdata);
     EXPECT_EQ(0, completions);
 
     const siginfo_t* expected_si = reinterpret_cast<siginfo_t*>(865);
-    EXPECT_EQ(0, handler(nullptr, expected_si, &child));
+    EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
     EXPECT_EQ(1, completions);
     EXPECT_EQ(expected_si, return_si);
 
     child.set_callback(std::bind([]() {}));
-    EXPECT_EQ(0, handler(nullptr, expected_si, &child));
+    EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(ChildTest, ConstructError)
@@ -120,6 +126,8 @@
 {
   protected:
     std::unique_ptr<Child> child;
+    sd_event_destroy_t destroy;
+    void* userdata;
 
     void SetUp()
     {
@@ -131,9 +139,17 @@
         EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid,
                                              options, testing::_, nullptr))
             .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0)));
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(Return(nullptr));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(mock, sd_event_source_set_destroy_callback(
+                                  expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(
+                mock, sd_event_source_set_userdata(expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+            EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+                .WillRepeatedly(ReturnPointee(&userdata));
+        }
         child = std::make_unique<Child>(*event, pid, options,
                                         [](Child&, const siginfo_t*) {});
     }
@@ -142,6 +158,7 @@
     {
         expect_destruct();
         child.reset();
+        destroy(userdata);
     }
 };
 
diff --git a/test/source/event.cpp b/test/source/event.cpp
index e4d7b2a..1d5a877 100644
--- a/test/source/event.cpp
+++ b/test/source/event.cpp
@@ -20,6 +20,7 @@
 
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 
@@ -46,14 +47,8 @@
 
     void expect_destruct()
     {
-        {
-            testing::InSequence sequence;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source,
-                                                          SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(expected_source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(expected_source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(expected_event))
             .WillOnce(Return(nullptr));
     }
@@ -63,9 +58,19 @@
 {
     EXPECT_CALL(mock, sd_event_ref(expected_event))
         .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     sd_event_handler_t handler;
     EXPECT_CALL(mock, sd_event_add_defer(expected_event, testing::_, testing::_,
                                          nullptr))
@@ -76,27 +81,38 @@
         completions++;
     };
     Defer defer(*event, std::move(callback));
-    EXPECT_EQ(&defer, userdata);
+    EXPECT_NE(&defer, userdata);
     EXPECT_FALSE(callback);
     EXPECT_EQ(0, completions);
 
-    EXPECT_EQ(0, handler(nullptr, &defer));
+    EXPECT_EQ(0, handler(nullptr, userdata));
     EXPECT_EQ(1, completions);
 
     defer.set_callback(std::bind([]() {}));
-    EXPECT_EQ(0, handler(nullptr, &defer));
+    EXPECT_EQ(0, handler(nullptr, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(EventTest, PostConstruct)
 {
     EXPECT_CALL(mock, sd_event_ref(expected_event))
         .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     sd_event_handler_t handler;
     EXPECT_CALL(mock, sd_event_add_post(expected_event, testing::_, testing::_,
                                         nullptr))
@@ -107,23 +123,34 @@
         completions++;
     };
     Post post(*event, std::move(callback));
-    EXPECT_EQ(&post, userdata);
+    EXPECT_NE(&post, userdata);
     EXPECT_FALSE(callback);
     EXPECT_EQ(0, completions);
 
-    EXPECT_EQ(0, handler(nullptr, &post));
+    EXPECT_EQ(0, handler(nullptr, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(EventTest, ExitConstruct)
 {
     EXPECT_CALL(mock, sd_event_ref(expected_event))
         .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     sd_event_handler_t handler;
     EXPECT_CALL(mock, sd_event_add_exit(expected_event, testing::_, testing::_,
                                         nullptr))
@@ -134,14 +161,15 @@
         completions++;
     };
     Exit exit(*event, std::move(callback));
-    EXPECT_EQ(&exit, userdata);
+    EXPECT_NE(&exit, userdata);
     EXPECT_FALSE(callback);
     EXPECT_EQ(0, completions);
 
-    EXPECT_EQ(0, handler(nullptr, &exit));
+    EXPECT_EQ(0, handler(nullptr, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(EventTest, ConstructFailure)
diff --git a/test/source/io.cpp b/test/source/io.cpp
index 89506b1..bafdeb8 100644
--- a/test/source/io.cpp
+++ b/test/source/io.cpp
@@ -20,6 +20,7 @@
 
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 
@@ -46,14 +47,8 @@
 
     void expect_destruct()
     {
-        {
-            testing::InSequence sequence;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source,
-                                                          SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(expected_source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(expected_source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(expected_event))
             .WillOnce(Return(nullptr));
     }
@@ -71,9 +66,19 @@
                                       testing::_, nullptr))
         .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&handler),
                         Return(0)));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     int completions = 0;
     int return_fd;
     uint32_t return_revents;
@@ -84,19 +89,20 @@
     };
     IO io(*event, fd, events, std::move(callback));
     EXPECT_FALSE(callback);
-    EXPECT_EQ(&io, userdata);
+    EXPECT_NE(&io, userdata);
     EXPECT_EQ(0, completions);
 
-    EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, &io));
+    EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata));
     EXPECT_EQ(1, completions);
     EXPECT_EQ(5, return_fd);
     EXPECT_EQ(EPOLLIN, return_revents);
 
     io.set_callback(std::bind([]() {}));
-    EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, &io));
+    EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(IOTest, ConstructError)
@@ -120,6 +126,8 @@
 {
   protected:
     std::unique_ptr<IO> io;
+    sd_event_destroy_t destroy;
+    void* userdata;
 
     void SetUp()
     {
@@ -131,9 +139,17 @@
         EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd,
                                           events, testing::_, nullptr))
             .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0)));
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(Return(nullptr));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(mock, sd_event_source_set_destroy_callback(
+                                  expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(
+                mock, sd_event_source_set_userdata(expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+            EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+                .WillRepeatedly(ReturnPointee(&userdata));
+        }
         io =
             std::make_unique<IO>(*event, fd, events, [](IO&, int, uint32_t) {});
     }
@@ -142,6 +158,7 @@
     {
         expect_destruct();
         io.reset();
+        destroy(userdata);
     }
 };
 
diff --git a/test/source/signal.cpp b/test/source/signal.cpp
index d3b53a7..209f2a7 100644
--- a/test/source/signal.cpp
+++ b/test/source/signal.cpp
@@ -21,6 +21,7 @@
 
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 
@@ -47,14 +48,8 @@
 
     void expect_destruct()
     {
-        {
-            testing::InSequence sequence;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source,
-                                                          SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(expected_source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(expected_source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(expected_event))
             .WillOnce(Return(nullptr));
     }
@@ -71,9 +66,19 @@
                                           testing::_, nullptr))
         .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<3>(&handler),
                         Return(0)));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     int completions = 0;
     const struct signalfd_siginfo* return_si;
     Signal::Callback callback = [&](Signal&,
@@ -83,20 +88,21 @@
     };
     Signal signal(*event, sig, std::move(callback));
     EXPECT_FALSE(callback);
-    EXPECT_EQ(&signal, userdata);
+    EXPECT_NE(&signal, userdata);
     EXPECT_EQ(0, completions);
 
     const struct signalfd_siginfo* expected_si =
         reinterpret_cast<struct signalfd_siginfo*>(865);
-    EXPECT_EQ(0, handler(nullptr, expected_si, &signal));
+    EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
     EXPECT_EQ(1, completions);
     EXPECT_EQ(expected_si, return_si);
 
     signal.set_callback(std::bind([]() {}));
-    EXPECT_EQ(0, handler(nullptr, expected_si, &signal));
+    EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
     EXPECT_EQ(1, completions);
 
     expect_destruct();
+    destroy(userdata);
 }
 
 TEST_F(SignalTest, ConstructError)
@@ -120,6 +126,8 @@
 {
   protected:
     std::unique_ptr<Signal> signal;
+    sd_event_destroy_t destroy;
+    void* userdata;
 
     void SetUp()
     {
@@ -130,9 +138,17 @@
         EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig,
                                               testing::_, nullptr))
             .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0)));
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(Return(nullptr));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(mock, sd_event_source_set_destroy_callback(
+                                  expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(
+                mock, sd_event_source_set_userdata(expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+            EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+                .WillRepeatedly(ReturnPointee(&userdata));
+        }
         signal = std::make_unique<Signal>(
             *event, sig, [](Signal&, const struct signalfd_siginfo*) {});
     }
@@ -141,6 +157,7 @@
     {
         expect_destruct();
         signal.reset();
+        destroy(userdata);
     }
 };
 
diff --git a/test/source/time.cpp b/test/source/time.cpp
index 96a920e..569d2c0 100644
--- a/test/source/time.cpp
+++ b/test/source/time.cpp
@@ -21,6 +21,7 @@
 
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 
@@ -47,13 +48,8 @@
 
     void expect_time_destroy(sd_event* event, sd_event_source* source)
     {
-        {
-            testing::InSequence sequence;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(event)).WillOnce(Return(nullptr));
     }
 };
@@ -77,12 +73,23 @@
                                   2000000, 50000, testing::_, nullptr))
         .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
                         Return(0)));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&userdata));
+    }
     Time<id> time(*event, expected_time, expected_accuracy,
                   std::move(callback));
     EXPECT_FALSE(callback);
+    EXPECT_NE(&time, userdata);
     EXPECT_EQ(expected_event, time.get_event().get());
     EXPECT_EQ(expected_source, time.get());
 
@@ -96,6 +103,7 @@
               saved_time);
 
     expect_time_destroy(expected_event, expected_source);
+    destroy(userdata);
 }
 
 TEST_F(TimeTest, ConstructError)
@@ -120,6 +128,8 @@
   protected:
     static constexpr ClockId id = ClockId::BootTime;
     std::unique_ptr<Time<id>> time;
+    sd_event_destroy_t destroy;
+    void* userdata;
 
     void SetUp()
     {
@@ -129,9 +139,17 @@
                                             CLOCK_BOOTTIME, 2000000, 50000,
                                             testing::_, nullptr))
             .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0)));
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(Return(nullptr));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(mock, sd_event_source_set_destroy_callback(
+                                  expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(
+                mock, sd_event_source_set_userdata(expected_source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+            EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+                .WillRepeatedly(ReturnPointee(&userdata));
+        }
         time = std::make_unique<Time<id>>(
             *event, Time<id>::TimePoint(std::chrono::seconds{2}),
             std::chrono::milliseconds{50},
@@ -142,6 +160,7 @@
     {
         expect_time_destroy(expected_event, expected_source);
         time.reset();
+        destroy(userdata);
     }
 };
 
diff --git a/test/utility/timer.cpp b/test/utility/timer.cpp
index f35a0c4..70fda1b 100644
--- a/test/utility/timer.cpp
+++ b/test/utility/timer.cpp
@@ -23,6 +23,7 @@
 using std::chrono::milliseconds;
 using testing::DoAll;
 using testing::Return;
+using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgPointee;
 using TestTimer = Timer<testClock>;
@@ -54,6 +55,7 @@
     const milliseconds starting_time2{30};
     sd_event_time_handler_t handler = nullptr;
     void* handler_userdata;
+    sd_event_destroy_t handler_destroy;
     std::unique_ptr<Event> event;
     std::unique_ptr<TestTimer> timer;
     std::function<void()> callback;
@@ -94,6 +96,7 @@
         {
             expectSetEnabled(source::Enabled::Off);
             timer.reset();
+            handler_destroy(handler_userdata);
         }
     }
 
@@ -116,10 +119,15 @@
         event = std::make_unique<Event>(expected_event, &mock);
         EXPECT_CALL(mock, sd_event_source_unref(expected_source))
             .WillRepeatedly(Return(nullptr));
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillRepeatedly(DoAll(SaveArg<1>(&handler_destroy), Return(0)));
         EXPECT_CALL(mock,
                     sd_event_source_set_userdata(expected_source, testing::_))
             .WillRepeatedly(
                 DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
+        EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+            .WillRepeatedly(ReturnPointee(&handler_userdata));
 
         // Having a callback proxy allows us to update the test callback
         // dynamically, without changing it inside the timer
@@ -349,9 +357,16 @@
     callback = [&]() { ++called; };
 
     expectNow(starting_time2);
+    sd_event_destroy_t local_destroy;
+    EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source2,
+                                                           testing::_))
+        .WillOnce(DoAll(SaveArg<1>(&local_destroy), Return(0)));
+    void* local_userdata;
     EXPECT_CALL(mock,
                 sd_event_source_set_userdata(expected_source2, testing::_))
-        .WillOnce(Return(nullptr));
+        .WillOnce(DoAll(SaveArg<1>(&local_userdata), Return(nullptr)));
+    EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source2))
+        .WillRepeatedly(ReturnPointee(&local_userdata));
     EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
                                         static_cast<clockid_t>(testClock),
                                         microseconds(starting_time2).count(),
@@ -368,6 +383,7 @@
 
     // Move assign
     local_timer = std::move(*timer);
+    local_destroy(local_userdata);
     timer.reset();
 
     // Move construct