592caf
From 441684c6c961edec1391562fb2f48ff997a6169e Mon Sep 17 00:00:00 2001
592caf
From: Lennart Poettering <lennart@poettering.net>
592caf
Date: Mon, 23 Nov 2020 15:38:00 +0100
592caf
Subject: [PATCH] sd-event: ref event loop while in sd_event_prepare() ot
592caf
 sd_event_run()
592caf
592caf
sd_event_prepare() invokes callbacks that might drop the last user ref
592caf
on our event loop. Let's make sure we keep an explicit ref around it, so
592caf
that we won't end up with an invalid pointer. Similar in sd_event_run().
592caf
592caf
Basically, any function that is publically callable that might end up
592caf
invoking callbacks should ref the relevant objects to be protected
592caf
against callbacks destroying these objects while we still want to access
592caf
them. We did this correctly in sd_event_dispatch() and sd_event_loop(),
592caf
but these are not the only ones which are callable from the outside.
592caf
592caf
(cherry picked from commit f814c871e65df8552a055dd887bc94b074037833)
592caf
592caf
Related: #1819868
592caf
---
592caf
 src/libsystemd/sd-event/sd-event.c | 15 +++++++++------
592caf
 1 file changed, 9 insertions(+), 6 deletions(-)
592caf
592caf
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
592caf
index 537a0b81d4..be1e6e5f53 100644
592caf
--- a/src/libsystemd/sd-event/sd-event.c
592caf
+++ b/src/libsystemd/sd-event/sd-event.c
592caf
@@ -3256,7 +3256,6 @@ static int event_prepare(sd_event *e) {
592caf
 
592caf
 static int dispatch_exit(sd_event *e) {
592caf
         sd_event_source *p;
592caf
-        _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
592caf
         int r;
592caf
 
592caf
         assert(e);
592caf
@@ -3267,7 +3266,7 @@ static int dispatch_exit(sd_event *e) {
592caf
                 return 0;
592caf
         }
592caf
 
592caf
-        ref = sd_event_ref(e);
592caf
+        _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
592caf
         e->iteration++;
592caf
         e->state = SD_EVENT_EXITING;
592caf
         r = source_dispatch(p);
592caf
@@ -3365,6 +3364,9 @@ _public_ int sd_event_prepare(sd_event *e) {
592caf
          * syscalls */
592caf
         assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
592caf
 
592caf
+        /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
592caf
+        _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
592caf
+
592caf
         if (e->exit_requested)
592caf
                 goto pending;
592caf
 
592caf
@@ -3549,9 +3551,8 @@ _public_ int sd_event_dispatch(sd_event *e) {
592caf
 
592caf
         p = event_next_pending(e);
592caf
         if (p) {
592caf
-                _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
592caf
+                _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
592caf
 
592caf
-                ref = sd_event_ref(e);
592caf
                 e->state = SD_EVENT_RUNNING;
592caf
                 r = source_dispatch(p);
592caf
                 e->state = SD_EVENT_INITIAL;
592caf
@@ -3600,6 +3601,9 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
592caf
                 }
592caf
         }
592caf
 
592caf
+        /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
592caf
+        _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
592caf
+
592caf
         r = sd_event_prepare(e);
592caf
         if (r == 0)
592caf
                 /* There was nothing? Then wait... */
592caf
@@ -3621,7 +3625,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
592caf
 }
592caf
 
592caf
 _public_ int sd_event_loop(sd_event *e) {
592caf
-        _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
592caf
         int r;
592caf
 
592caf
         assert_return(e, -EINVAL);
592caf
@@ -3629,7 +3632,7 @@ _public_ int sd_event_loop(sd_event *e) {
592caf
         assert_return(!event_pid_changed(e), -ECHILD);
592caf
         assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
592caf
 
592caf
-        ref = sd_event_ref(e);
592caf
+        _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
592caf
 
592caf
         while (e->state != SD_EVENT_FINISHED) {
592caf
                 r = sd_event_run(e, (uint64_t) -1);