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