]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: resolvers: Free new requester on error when linking a resolution
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 4 May 2026 06:47:58 +0000 (08:47 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 4 May 2026 14:33:56 +0000 (16:33 +0200)
If an error is triggered while the requester was allocated, it is not
immediately released. It is not really a memory leak because the requester
will be reused laster, on a next attempt, or released on deinit. For a
do-resolv action, the requester is released with the stream. So no leak
here. But it is probably not expected to keep a newly allocated requester in
case of error.

This patch could be backported as far as 2.6.

src/resolvers.c

index a151f60342bab4f171ba1fc4380b2e4aa79ab233..7049ca8d6dd0ae6b54905b7a2adb29d712253059 100644 (file)
@@ -2103,6 +2103,7 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
        struct stream         *stream = NULL;
        char **hostname_dn;
        int   hostname_dn_len, query_type;
+       int req_was_new = 0;
 
        enter_resolver_code();
        switch (requester_type) {
@@ -2112,6 +2113,7 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
                        if (!requester_locked)
                                HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
 
+                       req_was_new = !srv->resolv_requester;
                        req = resolv_get_requester(&srv->resolv_requester,
                                                   &srv->obj_type,
                                                   snr_resolution_cb,
@@ -2137,6 +2139,7 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
                case OBJ_TYPE_SRVRQ:
                        srvrq           = (struct resolv_srvrq *)requester;
 
+                       req_was_new = !srvrq->requester;
                        req = resolv_get_requester(&srvrq->requester,
                                                   &srvrq->obj_type,
                                                   snr_resolution_cb,
@@ -2153,6 +2156,7 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
                case OBJ_TYPE_STREAM:
                        stream          = (struct stream *)requester;
 
+                       req_was_new = !stream->resolv_ctx.requester;
                        req = resolv_get_requester(&stream->resolv_ctx.requester,
                                                   &stream->obj_type,
                                                   act_resolution_cb,
@@ -2174,6 +2178,7 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
                case OBJ_TYPE_ACME_RSLV: {
                        struct acme_rslv *acme_rslv = (struct acme_rslv *)requester;
 
+                       req_was_new = !acme_rslv->requester;
                        req = resolv_get_requester(&acme_rslv->requester,
                                                   &acme_rslv->obj_type,
                                                   acme_rslv->success_cb,
@@ -2203,9 +2208,36 @@ int resolv_link_resolution(void *requester, int requester_type, int requester_lo
        leave_resolver_code();
        return 0;
 
-  err:
+err:
        if (res && LIST_ISEMPTY(&res->requesters))
                resolv_free_resolution(res);
+       if (req_was_new) {
+               switch (requester_type) {
+                       case OBJ_TYPE_SERVER:
+                               srv->resolv_requester = NULL;
+                               pool_free(resolv_requester_pool, req);
+                               break;
+                       case OBJ_TYPE_SRVRQ:
+                               srvrq->requester = NULL;
+                               pool_free(resolv_requester_pool, req);
+                               break;
+                       case OBJ_TYPE_STREAM:
+                               stream->resolv_ctx.requester = NULL;
+                               pool_free(resolv_requester_pool, req);
+                               break;
+#if defined(HAVE_ACME)
+                       case OBJ_TYPE_ACME_RSLV: {
+                               struct acme_rslv *acme_rslv = (struct acme_rslv *)requester;
+                               acme_rslv->requester = NULL;
+                               pool_free(resolv_requester_pool, req);
+                               break;
+                       }
+#endif
+                       default:
+                               break;
+               }
+       }
+
        leave_resolver_code();
        return -1;
 }