]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: fwlc: Handle memory allocation failures.
authorOlivier Houchard <ohouchard@haproxy.com>
Wed, 1 Oct 2025 16:05:53 +0000 (18:05 +0200)
committerOlivier Houchard <cognet@ci0.org>
Wed, 1 Oct 2025 16:13:33 +0000 (18:13 +0200)
Properly handle memory allocation failures, by checking the return value
for pool_alloc(), and if it fails, make sure that the caller will take
it into account.
The only use of pool_alloc() in fwlc is to allocate the tree elements in
order to properly queue the server into the ebtree, so if that
allocation fails, just schedule the requeue tasklet, that will try
again, until it hopefully eventually succeeds.

This should be backported to 3.2.
This should fix github issue #3143.

src/lb_fwlc.c

index 0807459104a42ba596cbd99e90a0194972f18f3c..20a679e3af5a681a7d908b0ae3a5762468919bea 100644 (file)
@@ -165,9 +165,11 @@ static struct fwlc_tree_elt *fwlc_alloc_tree_elt(struct proxy *p, struct fwlc_tr
                                break;
                }
        }
-       if (!allocated_elt)
+       if (!allocated_elt) {
                tree_elt = pool_alloc(pool_head_fwlc_elt);
-       else
+               if (!tree_elt)
+                       return NULL;
+       } else
                tree_elt = allocated_elt;
 
        for (i = 0; i < FWLC_LISTS_NB; i++) {
@@ -195,6 +197,8 @@ static struct fwlc_tree_elt *fwlc_get_tree_elt(struct server *s, u32 key)
        if (!tree_elt) {
                /* No element available, we have to allocate one */
                tree_elt = fwlc_alloc_tree_elt(s->proxy, NULL);
+               if (!tree_elt)
+                       return NULL;
                tree_elt->lb_node.key = key;
                eb32_insert(s->lb_tree, &tree_elt->lb_node);
        }
@@ -228,6 +232,17 @@ static inline void fwlc_queue_srv(struct server *s, unsigned int eweight)
 
        key = inflight ? (inflight + 1) * SRV_EWGHT_MAX / eweight : 0;
        tree_elt = fwlc_get_tree_elt(s, key);
+       if (tree_elt == NULL) {
+               /*
+                * We failed to allocate memory for the tree_elt, just stop
+                * now and schedule the requeue tasklet which will take care
+                * of the queueing later.
+                * If the tasklet doesn't exist yet, then there is nothing to
+                * do, as it will be eventually scheduled after being created.
+                */
+               tasklet_wakeup(s->requeue_tasklet);
+               return;
+       }
        list_nb = statistical_prng_range(FWLC_LISTS_NB);
        MT_LIST_APPEND(&tree_elt->srv_list[list_nb], &s->lb_mt_list);
        s->tree_elt = tree_elt;
@@ -420,6 +435,14 @@ static void fwlc_srv_reposition(struct server *s)
                 * allocate one and insert it into the tree
                 */
                tree_elt = fwlc_alloc_tree_elt(s->proxy, allocated_elt);
+               if (tree_elt == NULL) {
+                       /* We failed to allocate memory, just try again later */
+                       HA_RWLOCK_RDUNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock);
+                       _HA_ATOMIC_STORE(&s->lb_lock, 0);
+                       if (s->requeue_tasklet)
+                               tasklet_wakeup(s->requeue_tasklet);
+                       return;
+               }
                if (tree_elt == allocated_elt)
                        allocated_elt = NULL;
                tree_elt->lb_node.key = new_key;