diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2025-01-20 12:32:47 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2025-01-20 12:32:47 -0500 |
commit | 34e6eca4ad9530918dcbc1d755eefc279782db9f (patch) | |
tree | 452e12814d15d3caf32ebc38158a1cbd061e8b30 /src | |
parent | be8aa86151fe540899c572cb1305c2ab7bbb52de (diff) | |
download | bfs-34e6eca4ad9530918dcbc1d755eefc279782db9f.tar.xz |
sighook: Fix sigreset() error handling
Diffstat (limited to 'src')
-rw-r--r-- | src/sighook.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/src/sighook.c b/src/sighook.c index 1783b83..a87bed5 100644 --- a/src/sighook.c +++ b/src/sighook.c @@ -295,18 +295,22 @@ static void rcu_list_remove(struct rcu_list *list, struct rcu_node *node) { rcu_destroy(&node->next); } -/** Iterate over an rcu_list. */ +/** + * Iterate over an rcu_list. + * + * It is save to `break` out of this loop, but `return` or `goto` will lead to + * a missed arc_put(). + */ #define for_rcu(type, node, list) \ for_rcu_(type, node, (list), node##_slot_, node##_prev_, node##_done_) #define for_rcu_(type, node, list, slot, prev, done) \ - /* This outer loop is just for declaring variables; it iterates once. */ \ - for (struct arc *slot, *prev, **done = NULL; !done && (done = &slot); ) \ + for (struct arc *slot, *prev, **done = NULL; !done; arc_put(slot), done = &slot) \ for (type *node = rcu_read(&list->head, &slot); \ - node || (arc_put(slot), false); \ - (prev = slot, \ - node = rcu_read(&((struct rcu_node *)node)->next, &slot), \ - arc_put(prev))) + node; \ + prev = slot, \ + node = rcu_read(&((struct rcu_node *)node)->next, &slot), \ + arc_put(prev)) struct sighook { /** The RCU list node (must be the first field). */ @@ -675,11 +679,14 @@ int sigreset(void) { return 0; } + int ret = 0; + for_rcu (struct sigsave, save, &saved) { if (sigaction(save->sig, &save->action, NULL) != 0) { - return -1; + ret = -1; + break; } } - return 0; + return ret; } |