summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-02-13 23:57:43 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-02-15 14:03:53 +0100
commit1bdf2790025e661e41894129eb390bb032b88585 (patch)
tree720435b6f2bb5c9ef4dbc8b3cb2b590e5378ddf7
parenta946fa9bb968ac197d7a99970e27388b751dca94 (diff)
downloadsystemd-1bdf2790025e661e41894129eb390bb032b88585.tar.gz
pid1: properly remove references to the unit from gc queue during final cleanup
When various references to the unit were dropped during cleanup in unit_free(), add_to_gc_queue() could be called on this unit. If the unit was previously in the gc queue (at the time when unit_free() was called on it), this wouldn't matter, because it'd have in_gc_queue still set even though it was already removed from the queue. But if it wasn't set, then the unit could be added to the queue. Then after unit_free() would deallocate the unit, we would be left with a dangling pointer in gc_queue. A unit could be added to the gc queue in two places called from unit_free(): in the job_install calls, and in unit_ref_unset(). The first was OK, because it was above the LIST_REMOVE(gc_queue,...) call, but the second was not, because it was after that. Move the all LIST_REMOVE() calls down.
-rw-r--r--src/core/unit.c42
1 files changed, 21 insertions, 21 deletions
diff --git a/src/core/unit.c b/src/core/unit.c
index 15cfe84e2f..5e619b0b07 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -610,27 +610,6 @@ void unit_free(Unit *u) {
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
bidi_set_free(u, u->dependencies[d]);
- if (u->type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
-
- if (u->in_load_queue)
- LIST_REMOVE(load_queue, u->manager->load_queue, u);
-
- if (u->in_dbus_queue)
- LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
-
- if (u->in_cleanup_queue)
- LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
-
- if (u->in_gc_queue)
- LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
-
- if (u->in_cgroup_realize_queue)
- LIST_REMOVE(cgroup_realize_queue, u->manager->cgroup_realize_queue, u);
-
- if (u->in_cgroup_empty_queue)
- LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
-
if (u->on_console)
manager_unref_console(u->manager);
@@ -650,6 +629,27 @@ void unit_free(Unit *u) {
while (u->refs_by_target)
unit_ref_unset(u->refs_by_target);
+ if (u->type != _UNIT_TYPE_INVALID)
+ LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
+
+ if (u->in_load_queue)
+ LIST_REMOVE(load_queue, u->manager->load_queue, u);
+
+ if (u->in_dbus_queue)
+ LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
+
+ if (u->in_gc_queue)
+ LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
+
+ if (u->in_cgroup_realize_queue)
+ LIST_REMOVE(cgroup_realize_queue, u->manager->cgroup_realize_queue, u);
+
+ if (u->in_cgroup_empty_queue)
+ LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
+
+ if (u->in_cleanup_queue)
+ LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
+
safe_close(u->ip_accounting_ingress_map_fd);
safe_close(u->ip_accounting_egress_map_fd);