details:   
https://github.com/nginx/njs/commit/0c0d4e50ec4d582b345bc64c12b737b109b7bc03
branches:  master
commit:    0c0d4e50ec4d582b345bc64c12b737b109b7bc03
user:      Dmitry Volyntsev <xei...@nginx.com>
date:      Wed, 21 May 2025 17:10:15 -0700
description:
QuickJS: added memory limit check for reuse queue.


---
 nginx/ngx_http_js_module.c   |  7 +++++++
 nginx/ngx_js.c               | 26 ++++++++++++++++++++++++++
 nginx/ngx_js.h               |  1 +
 nginx/ngx_stream_js_module.c |  7 +++++++
 4 files changed, 41 insertions(+)

diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c
index 28798172..1e0a927f 100644
--- a/nginx/ngx_http_js_module.c
+++ b/nginx/ngx_http_js_module.c
@@ -433,6 +433,13 @@ static ngx_command_t  ngx_http_js_commands[] = {
       offsetof(ngx_http_js_loc_conf_t, reuse),
       NULL },
 
+    { ngx_string("js_context_reuse_max_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_js_loc_conf_t, reuse_max_size),
+      NULL },
+
     { ngx_string("js_import"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
       ngx_js_import,
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c
index e4bae32a..515218b9 100644
--- a/nginx/ngx_js.c
+++ b/nginx/ngx_js.c
@@ -1133,6 +1133,7 @@ ngx_engine_qjs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
     JSRuntime            *rt;
     JSContext            *cx;
     JSClassID             class_id;
+    JSMemoryUsage         stats;
     ngx_qjs_event_t      *event;
     ngx_js_opaque_t      *opaque;
     njs_rbtree_node_t    *node;
@@ -1198,6 +1199,28 @@ ngx_engine_qjs_destroy(ngx_engine_t *e, ngx_js_ctx_t 
*ctx,
             cln->data = conf->reuse_queue;
         }
 
+        /*
+         * After the request object is freed, the runtime's memory usage should
+         * be low. It can only remain high if the global scope was
+         * modified.
+         *
+         * To prevent unlimited memory consumption growth, check whether memory
+         * usage exceeds the configured limit. The check is performed rarely to
+         * avoid performance impact of JS_ComputeMemoryUsage() which is slow.
+         */
+
+        if ((ngx_random() & 0xff) == 1) {
+            JS_ComputeMemoryUsage(JS_GetRuntime(cx), &stats);
+
+            if ((size_t) stats.malloc_size > conf->reuse_max_size) {
+                ngx_log_error(NGX_LOG_WARN, ctx->log, 0,
+                              "js remaining memory usage of the context "
+                              "exceeds \"js_context_reuse_max_size\" limit: %L"
+                              ", not reusing it", stats.malloc_size);
+                goto free_ctx;
+            }
+        }
+
         if (ngx_js_queue_push(conf->reuse_queue, cx) != NGX_OK) {
             goto free_ctx;
         }
@@ -3950,6 +3973,7 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
     conf->preload_objects = NGX_CONF_UNSET_PTR;
 
     conf->reuse = NGX_CONF_UNSET_SIZE;
+    conf->reuse_max_size = NGX_CONF_UNSET_SIZE;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
     conf->max_response_body_size = NGX_CONF_UNSET_SIZE;
     conf->timeout = NGX_CONF_UNSET_MSEC;
@@ -4059,6 +4083,8 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void 
*child,
 
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
     ngx_conf_merge_size_value(conf->reuse, prev->reuse, 128);
+    ngx_conf_merge_size_value(conf->reuse_max_size, prev->reuse_max_size,
+                              4 * 1024 * 1024);
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384);
     ngx_conf_merge_size_value(conf->max_response_body_size,
                               prev->max_response_body_size, 1048576);
diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h
index 122881af..99330f88 100644
--- a/nginx/ngx_js.h
+++ b/nginx/ngx_js.h
@@ -122,6 +122,7 @@ typedef struct {
     ngx_uint_t             type;                                              \
     ngx_engine_t          *engine;                                            \
     ngx_uint_t             reuse;                                             \
+    size_t                 reuse_max_size;                                    \
     ngx_js_queue_t        *reuse_queue;                                       \
     ngx_str_t              cwd;                                               \
     ngx_array_t           *imports;                                           \
diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c
index fb58cdc6..328ce581 100644
--- a/nginx/ngx_stream_js_module.c
+++ b/nginx/ngx_stream_js_module.c
@@ -264,6 +264,13 @@ static ngx_command_t  ngx_stream_js_commands[] = {
       offsetof(ngx_stream_js_srv_conf_t, reuse),
       NULL },
 
+    { ngx_string("js_context_reuse_max_size"),
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_STREAM_SRV_CONF_OFFSET,
+      offsetof(ngx_stream_js_srv_conf_t, reuse_max_size),
+      NULL },
+
     { ngx_string("js_import"),
       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE13,
       ngx_js_import,
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel

Reply via email to