[nginx] Limit conn: fixed counter leak on memory allocation errors.

Maxim Dounin mdounin at mdounin.ru
Mon Jul 7 04:29:40 UTC 2025


details:   http://freenginx.org/hg/nginx/rev/722e252fcabe
branches:  
changeset: 9389:722e252fcabe
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Mon Jul 07 04:34:18 2025 +0300
description:
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.

diffstat:

 src/http/modules/ngx_http_limit_conn_module.c |  16 ++++++++++++++++
 src/stream/ngx_stream_limit_conn_module.c     |  16 ++++++++++++++++
 2 files changed, 32 insertions(+), 0 deletions(-)

diffs (80 lines):

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