[PATCH 1 of 2] Limit conn: fixed counter leak on memory allocation errors

Maxim Dounin mdounin at mdounin.ru
Wed Jul 2 02:00:33 UTC 2025


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1751421418 -10800
#      Wed Jul 02 04:56:58 2025 +0300
# Node ID be87e6012ac4fdea00597d075dcfe116beecdef2
# Parent  1588a8af97be86864f9c4da50d328527de14ae21
Limit conn: fixed counter leak on memory allocation errors.

Previously, if ngx_pool_cleanup_add() failed, already incremented connection
counter was left as is, eventually resulting in unexpected connection
limiting or shared memory exhaustion.  Fix is to decrement the counter
by calling the cleanup handler with data on stack.

diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c
--- a/src/http/modules/ngx_http_limit_conn_module.c
+++ b/src/http/modules/ngx_http_limit_conn_module.c
@@ -60,6 +60,8 @@ static ngx_rbtree_node_t *ngx_http_limit
     ngx_str_t *key, uint32_t hash);
 static void ngx_http_limit_conn_cleanup(void *data);
 static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
+static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone,
+    ngx_rbtree_node_t *node);
 
 static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
@@ -294,6 +296,7 @@ ngx_http_limit_conn_handler(ngx_http_req
         cln = ngx_pool_cleanup_add(r->pool,
                                    sizeof(ngx_http_limit_conn_cleanup_t));
         if (cln == NULL) {
+            ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node);
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
@@ -433,6 +436,19 @@ ngx_http_limit_conn_cleanup_all(ngx_pool
 }
 
 
+static void
+ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone,
+    ngx_rbtree_node_t *node)
+{
+    ngx_http_limit_conn_cleanup_t  lccln;
+
+    lccln.shm_zone = shm_zone;
+    lccln.node = node;
+
+    ngx_http_limit_conn_cleanup(&lccln);
+}
+
+
 static ngx_int_t
 ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
 {
diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c
--- a/src/stream/ngx_stream_limit_conn_module.c
+++ b/src/stream/ngx_stream_limit_conn_module.c
@@ -59,6 +59,8 @@ static ngx_rbtree_node_t *ngx_stream_lim
     ngx_str_t *key, uint32_t hash);
 static void ngx_stream_limit_conn_cleanup(void *data);
 static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool);
+static void ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone,
+    ngx_rbtree_node_t *node);
 
 static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s,
     ngx_stream_variable_value_t *v, uintptr_t data);
@@ -274,6 +276,7 @@ ngx_stream_limit_conn_handler(ngx_stream
         cln = ngx_pool_cleanup_add(s->connection->pool,
                                    sizeof(ngx_stream_limit_conn_cleanup_t));
         if (cln == NULL) {
+            ngx_stream_limit_conn_cleanup_node(limits[i].shm_zone, node);
             return NGX_ERROR;
         }
 
@@ -414,6 +417,19 @@ ngx_stream_limit_conn_cleanup_all(ngx_po
 }
 
 
+static void
+ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone,
+    ngx_rbtree_node_t *node)
+{
+    ngx_stream_limit_conn_cleanup_t  lccln;
+
+    lccln.shm_zone = shm_zone;
+    lccln.node = node;
+
+    ngx_stream_limit_conn_cleanup(&lccln);
+}
+
+
 static ngx_int_t
 ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
 {



More information about the nginx-devel mailing list