From ad7813844a9ff4c5936f4465039cd66c890a5702 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 09:36:32 +0100 Subject: [PATCH 1/6] mkosi: add coccinelle to the debian tools tree too It is already part of the fedora/opensues tools tree. It must have slipped through for Debian so lets add it. --- mkosi/mkosi.tools.conf/mkosi.conf.d/debian-ubuntu.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/mkosi/mkosi.tools.conf/mkosi.conf.d/debian-ubuntu.conf b/mkosi/mkosi.tools.conf/mkosi.conf.d/debian-ubuntu.conf index 4bd4c12fd9..613d9d87d9 100644 --- a/mkosi/mkosi.tools.conf/mkosi.conf.d/debian-ubuntu.conf +++ b/mkosi/mkosi.tools.conf/mkosi.conf.d/debian-ubuntu.conf @@ -8,6 +8,7 @@ Distribution=|ubuntu PrepareScripts=%D/mkosi/mkosi.images/build/mkosi.conf.d/debian-ubuntu/mkosi.prepare Packages= clang-tidy + coccinelle lcov mypy shellcheck From 69d54d521330f40d4fe88107760b5d878fdf4715 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 09:46:33 +0100 Subject: [PATCH 2/6] cleanup: address review feedback from claude Trivial ordering/modernizing change that got highlighted by claude and refined by keszybz to move to the modern systemd style. Thanks to keszybz for suggesting this. --- src/import/qcow2-util.c | 4 +--- src/resolve/resolved-dns-stub.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c index dd5c3c23ec..fe0c8a2620 100644 --- a/src/import/qcow2-util.c +++ b/src/import/qcow2-util.c @@ -154,9 +154,7 @@ static int normalize_offset( POINTER_MAY_BE_NULL(compressed); POINTER_MAY_BE_NULL(compressed_size); - uint64_t q; - - q = be64toh(p); + uint64_t q = be64toh(p); if (q & QCOW2_COMPRESSED) { uint64_t sz, csize_shift, csize_mask; diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 298db3ae78..91ea30e0e2 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -83,9 +83,7 @@ int dns_stub_listener_extra_new( assert(ret); - DnsStubListenerExtra *l; - - l = new(DnsStubListenerExtra, 1); + DnsStubListenerExtra *l = new(DnsStubListenerExtra, 1); if (!l) return -ENOMEM; From f3c49a597f25768da105f600a80f00ac6c3c5412 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 10:24:18 +0100 Subject: [PATCH 3/6] nspawn: make check-pointer-deref clean Add the needed assert changes to make the code clean for the new check-pointer-deref script. --- meson.build | 1 - src/nspawn/nspawn-oci.c | 11 ++++++++--- src/nspawn/nspawn.c | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 5c02ab8664..deeb90a37e 100644 --- a/meson.build +++ b/meson.build @@ -2982,7 +2982,6 @@ if spatch.found() 'src/journal/', 'src/libsystemd/', 'src/network/', - 'src/nspawn/', 'src/shared/', # libc/ has no assert() or systemd-headers so leave it 'src/libc/', diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index 29091bd82c..93fd214329 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -1489,6 +1489,8 @@ static int oci_resources(const char *name, sd_json_variant *v, sd_json_dispatch_ static bool sysctl_key_valid(const char *s) { bool dot = true; + POINTER_MAY_BE_NULL(s); + /* Note that we are a bit stricter here than in systemd-sysctl, as that inherited semantics from the old sysctl * tool, which were really weird (as it swaps / and . in both ways) */ @@ -1546,7 +1548,6 @@ static int oci_sysctl(const char *name, sd_json_variant *v, sd_json_dispatch_fla #if HAVE_SECCOMP static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) { - static const struct { const char *name; uint32_t action; @@ -1563,6 +1564,8 @@ static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) { * here */ }; + assert(ret); + FOREACH_ELEMENT(i, table) if (streq_ptr(name, i->name)) { *ret = i->action; @@ -1573,7 +1576,6 @@ static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) { } static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) { - static const struct { const char *name; uint32_t arch; @@ -1605,6 +1607,8 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) { { "SCMP_ARCH_X86_64", SCMP_ARCH_X86_64 }, }; + assert(ret); + FOREACH_ELEMENT(i, table) if (streq_ptr(i->name, name)) { *ret = i->arch; @@ -1615,7 +1619,6 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) { } static int oci_seccomp_compare_from_string(const char *name, enum scmp_compare *ret) { - static const struct { const char *name; enum scmp_compare op; @@ -1629,6 +1632,8 @@ static int oci_seccomp_compare_from_string(const char *name, enum scmp_compare * { "SCMP_CMP_MASKED_EQ", SCMP_CMP_MASKED_EQ }, }; + assert(ret); + FOREACH_ELEMENT(i, table) if (streq_ptr(i->name, name)) { *ret = i->op; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 84e94e845a..1740ab4d6e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2981,6 +2981,7 @@ static int wait_for_container(PidRef *pid, ContainerStatus *container) { int r; assert(pidref_is_set(pid)); + assert(container); r = pidref_wait_for_terminate(pid, &status); if (r < 0) @@ -4723,6 +4724,8 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r static int setup_notify_parent(sd_event *event, int fd, PidRef *inner_child_pid, sd_event_source **notify_event_source) { int r; + assert(notify_event_source); + if (fd < 0) return 0; From 162613025445b96398f73574aca1cf70681da39a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 10:48:27 +0100 Subject: [PATCH 4/6] journal: make check-pointer-deref clean Add the needed assert changes to make the code clean for the new check-pointer-deref script. --- meson.build | 1 - src/journal/journald-audit.c | 2 ++ src/journal/journald-manager.c | 2 ++ src/journal/journald-native.c | 6 ++++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index deeb90a37e..bb4a2fbeea 100644 --- a/meson.build +++ b/meson.build @@ -2979,7 +2979,6 @@ if spatch.found() coccinelle_exclude = [ 'src/basic/', 'src/core/', - 'src/journal/', 'src/libsystemd/', 'src/network/', 'src/shared/', diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index fa6ba50b37..173fe9944a 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -158,6 +158,8 @@ static int map_generic_field( char *c, *t; int r; + assert(p); + /* Implements fallback mappings for all fields we don't know */ for (e = *p; e < *p + 16; e++) { diff --git a/src/journal/journald-manager.c b/src/journal/journald-manager.c index 8d95280fc6..3abc0d3869 100644 --- a/src/journal/journald-manager.c +++ b/src/journal/journald-manager.c @@ -135,6 +135,8 @@ static int manager_determine_path_usage( } static void cache_space_invalidate(JournalStorageSpace *space) { + assert(space); + zero(*space); } diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index d61e8f5a74..1e2a872c6e 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -45,6 +45,10 @@ static void manager_process_entry_meta( char **message, pid_t *object_pid) { + assert(priority); + assert(identifier); + assert(message); + /* We need to determine the priority of this entry for the rate limiting logic */ if (l == 10 && @@ -113,6 +117,8 @@ static int manager_process_entry( const char *p; int r = 1; + assert(remaining); + p = buffer; while (*remaining > 0) { From 3e9eaf45f022d116d31bd7906b1bcfdba2a88ecc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 12:02:32 +0100 Subject: [PATCH 5/6] network: make check-pointer-deref clean Add the needed assert changes to make the code clean for the new check-pointer-deref script. --- meson.build | 1 - src/network/generator/network-generator.c | 1 + src/network/netdev/macsec.c | 1 + src/network/netdev/netdev.c | 1 + src/network/networkctl-status-system.c | 3 +++ src/network/networkd-dhcp-common.c | 1 + src/network/networkd-dhcp-prefix-delegation.c | 1 + src/network/networkd-dhcp-server.c | 1 + src/network/networkd-link.c | 1 + src/network/networkd-radv.c | 1 + src/network/networkd-routing-policy-rule.c | 2 ++ src/network/networkd-wwan.c | 1 + 12 files changed, 14 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bb4a2fbeea..674c2fef64 100644 --- a/meson.build +++ b/meson.build @@ -2980,7 +2980,6 @@ if spatch.found() 'src/basic/', 'src/core/', 'src/libsystemd/', - 'src/network/', 'src/shared/', # libc/ has no assert() or systemd-headers so leave it 'src/libc/', diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c index d0204366fb..2c3a8bf6aa 100644 --- a/src/network/generator/network-generator.c +++ b/src/network/generator/network-generator.c @@ -119,6 +119,7 @@ static int address_new( assert(network); assert(IN_SET(family, AF_INET, AF_INET6)); assert(addr); + POINTER_MAY_BE_NULL(peer); address = new(Address, 1); if (!address) diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 0b999b4b8a..9f3ddcc2b1 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -125,6 +125,7 @@ static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel ** ReceiveChannel *c; assert(s); + assert(ret); c = new(ReceiveChannel, 1); if (!c) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 393114aa7b..bde8d2db05 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -277,6 +277,7 @@ static int netdev_attach_name_full(NetDev *netdev, const char *name, Hashmap **n assert(netdev); assert(name); + assert(netdevs); r = hashmap_ensure_put(netdevs, &string_hash_ops, name, netdev); if (r == -ENOMEM) diff --git a/src/network/networkctl-status-system.c b/src/network/networkctl-status-system.c index bb1b5d1377..20a4c2be91 100644 --- a/src/network/networkctl-status-system.c +++ b/src/network/networkctl-status-system.c @@ -20,6 +20,9 @@ static int ifindex_str_compare_func(char * const *a, char * const *b) { size_t al, bl; int r; + assert(a); + assert(b); + al = strlen_ptr(*a); bl = strlen_ptr(*b); diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 619c2f6377..3e7cca991b 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -276,6 +276,7 @@ int link_get_captive_portal(Link *link, const char **ret) { int r; assert(link); + assert(ret); if (!link->network) { *ret = NULL; diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index f53d7d1c5a..e734b0171d 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -557,6 +557,7 @@ static int dhcp_pd_get_preferred_subnet_prefix( assert(link->manager); assert(link->network); assert(pd_prefix); + assert(ret); if (link->network->dhcp_pd_subnet_id >= 0) { /* If the link has a preference for a particular subnet id try to allocate that */ diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 24ae1bbe89..23ee3024e9 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -326,6 +326,7 @@ void manager_toggle_dhcp4_server_state(Manager *manager, bool start) { static int dhcp_server_find_uplink(Link *link, Link **ret) { assert(link); + assert(ret); if (link->network->dhcp_server_uplink_name) return link_get_by_name(link->manager, link->network->dhcp_server_uplink_name, ret); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 57b074e1be..c6bc8fc4b1 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -862,6 +862,7 @@ static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) { assert(link); assert(carrier); + assert(h); if (link == carrier) return 0; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 0ef292bdf2..a71e01dfbf 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -423,6 +423,7 @@ static int radv_find_uplink(Link *link, Link **ret) { int r; assert(link); + assert(ret); if (link->network->router_uplink_name) return link_get_by_name(link->manager, link->network->router_uplink_name, ret); diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index eb60d315bd..1cefad29de 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -99,6 +99,8 @@ DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_unref); static int routing_policy_rule_new(RoutingPolicyRule **ret) { RoutingPolicyRule *rule; + assert(ret); + rule = new(RoutingPolicyRule, 1); if (!rule) return -ENOMEM; diff --git a/src/network/networkd-wwan.c b/src/network/networkd-wwan.c index b84ace1301..525660ad8f 100644 --- a/src/network/networkd-wwan.c +++ b/src/network/networkd-wwan.c @@ -235,6 +235,7 @@ int link_get_modem(Link *link, Modem **ret) { assert(link); assert(link->manager); assert(link->ifname); + assert(ret); HASHMAP_FOREACH(modem, link->manager->modems_by_path) if (modem->port_name && streq(modem->port_name, link->ifname)) { From 57e5c9eea600913173e24ee40c583912e52cfee0 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sat, 28 Mar 2026 12:35:54 +0100 Subject: [PATCH 6/6] core: make check-pointer-deref clean Add the needed assert changes to make the code clean for the new check-pointer-deref script. --- meson.build | 1 - src/core/bpf-firewall.c | 2 ++ src/core/cgroup.c | 4 ++++ src/core/emergency-action.c | 2 ++ src/core/job.c | 7 +++++++ src/core/load-fragment.c | 6 ++++++ src/core/manager.c | 2 ++ src/core/mount.c | 2 ++ src/core/path.c | 1 + src/core/scope.c | 2 ++ src/core/smack-setup.c | 3 +++ src/core/socket.c | 2 ++ src/core/swap.c | 2 ++ src/core/timer.c | 1 + src/core/unit.c | 1 + src/core/varlink-execute.c | 3 +++ 16 files changed, 40 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 674c2fef64..c9e96b2591 100644 --- a/meson.build +++ b/meson.build @@ -2978,7 +2978,6 @@ if spatch.found() # Remove directories from this list as they are cleaned up. coccinelle_exclude = [ 'src/basic/', - 'src/core/', 'src/libsystemd/', 'src/shared/', # libc/ has no assert() or systemd-headers so leave it diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c index b0c54d3134..bc5d7f0351 100644 --- a/src/core/bpf-firewall.c +++ b/src/core/bpf-firewall.c @@ -661,6 +661,8 @@ static int attach_custom_bpf_progs(Unit *u, const char *path, int attach_type, S int r; assert(u); + assert(set); + assert(set_installed); set_clear(*set_installed); r = set_ensure_allocated(set_installed, &bpf_program_hash_ops); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 514dabf371..7bcd6777df 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -313,6 +313,8 @@ static int unit_compare_memory_limit(Unit *u, const char *property_name, uint64_ * - ret_kernel_value will contain the actual value presented by the kernel. */ assert(u); + assert(ret_unit_value); + assert(ret_kernel_value); /* The root slice doesn't have any controller files, so we can't compare anything. */ if (unit_has_name(u, SPECIAL_ROOT_SLICE)) @@ -3189,6 +3191,8 @@ static int cg_bpf_mask_supported(CGroupMask *ret) { CGroupMask mask = 0; int r; + assert(ret); + /* BPF-based firewall, device access control, and pinned foreign prog */ if (bpf_program_supported() > 0) mask |= CGROUP_MASK_BPF_FIREWALL | diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 439228c899..b9a5c66ebf 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -240,6 +240,8 @@ int parse_emergency_action( EmergencyAction x; + assert(ret); + x = emergency_action_from_string(value); if (x < 0) return -EINVAL; diff --git a/src/core/job.c b/src/core/job.c index 1cac09bd06..638e6e759e 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -510,6 +510,8 @@ JobType job_type_collapse(JobType t, Unit *u) { int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) { JobType t; + assert(a); + t = job_type_lookup_merge(*a, b); if (t < 0) return -EEXIST; @@ -1523,6 +1525,11 @@ void job_add_to_gc_queue(Job *j) { } static int job_compare_id(Job * const *a, Job * const *b) { + assert(a); + assert(b); + assert(*a); + assert(*b); + return CMP((*a)->id, (*b)->id); } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cef01ab776..840804fcf8 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -88,6 +88,8 @@ static int parse_socket_protocol(const char *s) { int parse_crash_chvt(const char *value, int *data) { int b; + assert(data); + if (safe_atoi(value, data) >= 0) return 0; @@ -107,6 +109,8 @@ int parse_confirm_spawn(const char *value, char **console) { char *s; int r; + assert(console); + r = value ? parse_boolean(value) : 1; if (r == 0) { *console = NULL; @@ -565,6 +569,8 @@ static int patch_var_run( const char *e; char *z; + assert(path); + e = path_startswith(*path, "/var/run/"); if (!e) return 0; diff --git a/src/core/manager.c b/src/core/manager.c index e8c5f00895..a5af434e5e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1982,6 +1982,8 @@ Manager* manager_reloading_start(Manager *m) { } void manager_reloading_stopp(Manager **m) { + assert(m); + if (*m) { assert((*m)->n_reloading > 0); (*m)->n_reloading--; diff --git a/src/core/mount.c b/src/core/mount.c index 680e376feb..46e157af20 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -2003,6 +2003,8 @@ static int mount_get_timeout(Unit *u, usec_t *timeout) { usec_t t; int r; + assert(timeout); + if (!m->timer_event_source) return 0; diff --git a/src/core/path.c b/src/core/path.c index 789ef9e25d..18a5e140f1 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -931,6 +931,7 @@ static int activation_details_path_deserialize(const char *key, const char *valu assert(key); assert(value); + POINTER_MAY_BE_NULL(details); if (!details || !*details) return -EINVAL; diff --git a/src/core/scope.c b/src/core/scope.c index d36b27c537..21520d9d19 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -483,6 +483,8 @@ static int scope_get_timeout(Unit *u, usec_t *timeout) { usec_t t; int r; + assert(timeout); + if (!s->timer_event_source) return 0; diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 1e8e2b54e5..46c7d0a6e8 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -26,6 +26,9 @@ static int fdopen_unlocked_at(int dfd, const char *dir, const char *name, int *s int fd, r; FILE *f; + assert(status); + assert(ret_file); + fd = openat(dfd, name, O_RDONLY|O_CLOEXEC); if (fd < 0) { if (*status == 0) diff --git a/src/core/socket.c b/src/core/socket.c index 43f61e456d..f911f1758f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3525,6 +3525,8 @@ static int socket_get_timeout(Unit *u, usec_t *timeout) { usec_t t; int r; + assert(timeout); + if (!s->timer_event_source) return 0; diff --git a/src/core/swap.c b/src/core/swap.c index 5de1dccf42..960d831c5c 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1427,6 +1427,8 @@ static int swap_get_timeout(Unit *u, usec_t *timeout) { usec_t t; int r; + assert(timeout); + if (!s->timer_event_source) return 0; diff --git a/src/core/timer.c b/src/core/timer.c index c591fcd469..510d8e1995 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -940,6 +940,7 @@ static int activation_details_timer_deserialize(const char *key, const char *val assert(key); assert(value); + POINTER_MAY_BE_NULL(details); if (!details || !*details) return -EINVAL; diff --git a/src/core/unit.c b/src/core/unit.c index 9af7fb5140..41f536ce1f 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -6377,6 +6377,7 @@ int unit_clean(Unit *u, ExecCleanMask mask) { int unit_can_clean(Unit *u, ExecCleanMask *ret) { assert(u); + assert(ret); if (!UNIT_VTABLE(u)->clean || u->load_state != UNIT_LOADED) { diff --git a/src/core/varlink-execute.c b/src/core/varlink-execute.c index e6efd59895..ccb454c8c2 100644 --- a/src/core/varlink-execute.c +++ b/src/core/varlink-execute.c @@ -781,6 +781,9 @@ static int set_credential_build_json(sd_json_variant **ret, const char *name, vo int unit_exec_context_build_json(sd_json_variant **ret, const char *name, void *userdata) { Unit *u = ASSERT_PTR(userdata); ExecContext *c = unit_get_exec_context(u); + + assert(ret); + if (!c) { *ret = NULL; return 0;