9ab0c5
From 019b19130bcba9d88c0328b40f2639e6ebbb513c Mon Sep 17 00:00:00 2001
9ab0c5
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
9ab0c5
Date: Tue, 13 Feb 2018 23:57:43 +0100
9ab0c5
Subject: [PATCH] pid1: properly remove references to the unit from gc queue
9ab0c5
 during final cleanup
9ab0c5
9ab0c5
When various references to the unit were dropped during cleanup in unit_free(),
9ab0c5
add_to_gc_queue() could be called on this unit. If the unit was previously in
9ab0c5
the gc queue (at the time when unit_free() was called on it), this wouldn't
9ab0c5
matter, because it'd have in_gc_queue still set even though it was already
9ab0c5
removed from the queue. But if it wasn't set, then the unit could be added to
9ab0c5
the queue. Then after unit_free() would deallocate the unit, we would be left
9ab0c5
with a dangling pointer in gc_queue.
9ab0c5
9ab0c5
A unit could be added to the gc queue in two places called from unit_free():
9ab0c5
in the job_install calls, and in unit_ref_unset(). The first was OK, because
9ab0c5
it was above the LIST_REMOVE(gc_queue,...) call, but the second was not, because
9ab0c5
it was after that. Move the all LIST_REMOVE() calls down.
9ab0c5
9ab0c5
(cherry picked from commit 1bdf2790025e661e41894129eb390bb032b88585)
9ab0c5
(cherry picked from commit 8f1df942e2237124f7559176081af7ac631d3422)
9ab0c5
9ab0c5
Related: #1729228
9ab0c5
---
9ab0c5
 src/core/unit.c | 34 +++++++++++++++++-----------------
9ab0c5
 1 file changed, 17 insertions(+), 17 deletions(-)
9ab0c5
9ab0c5
diff --git a/src/core/unit.c b/src/core/unit.c
9ab0c5
index 63f00acc0a..def36a0930 100644
9ab0c5
--- a/src/core/unit.c
9ab0c5
+++ b/src/core/unit.c
9ab0c5
@@ -506,23 +506,6 @@ void unit_free(Unit *u) {
9ab0c5
         for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
9ab0c5
                 bidi_set_free(u, u->dependencies[d]);
9ab0c5
 
9ab0c5
-        if (u->type != _UNIT_TYPE_INVALID)
9ab0c5
-                LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
9ab0c5
-
9ab0c5
-        if (u->in_load_queue)
9ab0c5
-                LIST_REMOVE(load_queue, u->manager->load_queue, u);
9ab0c5
-
9ab0c5
-        if (u->in_dbus_queue)
9ab0c5
-                LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
9ab0c5
-
9ab0c5
-        if (u->in_cleanup_queue)
9ab0c5
-                LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
9ab0c5
-
9ab0c5
-        if (u->in_gc_queue) {
9ab0c5
-                LIST_REMOVE(gc_queue, u->manager->gc_queue, u);
9ab0c5
-                u->manager->n_in_gc_queue--;
9ab0c5
-        }
9ab0c5
-
9ab0c5
         if (u->in_target_deps_queue)
9ab0c5
                 LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
9ab0c5
 
9ab0c5
@@ -543,6 +526,23 @@ void unit_free(Unit *u) {
9ab0c5
         while (u->refs_by_target)
9ab0c5
                 unit_ref_unset(u->refs_by_target);
9ab0c5
 
9ab0c5
+        if (u->type != _UNIT_TYPE_INVALID)
9ab0c5
+                LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
9ab0c5
+
9ab0c5
+        if (u->in_load_queue)
9ab0c5
+                LIST_REMOVE(load_queue, u->manager->load_queue, u);
9ab0c5
+
9ab0c5
+        if (u->in_dbus_queue)
9ab0c5
+                LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
9ab0c5
+
9ab0c5
+        if (u->in_cleanup_queue)
9ab0c5
+                LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
9ab0c5
+
9ab0c5
+        if (u->in_gc_queue) {
9ab0c5
+                LIST_REMOVE(gc_queue, u->manager->gc_queue, u);
9ab0c5
+                u->manager->n_in_gc_queue--;
9ab0c5
+        }
9ab0c5
+
9ab0c5
         condition_free_list(u->conditions);
9ab0c5
         condition_free_list(u->asserts);
9ab0c5