[njs] Change: the default JS stack size is reduced to 64k.

Dmitry Volyntsev xeioex at nginx.com
Thu Nov 10 17:34:10 UTC 2022


details:   https://hg.nginx.org/njs/rev/581c321d4015
branches:  
changeset: 1993:581c321d4015
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Nov 10 09:33:36 2022 -0800
description:
Change: the default JS stack size is reduced to 64k.

After 86784a68e8c8 (Computed goto) the size of a stack frame
njs_vmcode_interpreter() when -O0 is specified during compilation
increased significantly.  This might cause system stack overflow for very
deep recursive calls because system stack is exausted faster than JS
stack.

It is possible now to specify JS stack size for CLI.

diffstat:

 src/njs.h                |   2 ++
 src/njs_function.c       |   6 +++---
 src/njs_shell.c          |  18 ++++++++++++++++--
 src/njs_vm.c             |   3 +++
 src/njs_vm.h             |   4 ++--
 src/njs_vmcode.c         |   2 +-
 src/test/njs_unit_test.c |   2 +-
 7 files changed, 28 insertions(+), 9 deletions(-)

diffs (163 lines):

diff -r 62b475cce018 -r 581c321d4015 src/njs.h
--- a/src/njs.h	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs.h	Thu Nov 10 09:33:36 2022 -0800
@@ -254,6 +254,8 @@ typedef struct {
     char                            **argv;
     njs_uint_t                      argc;
 
+    njs_uint_t                      max_stack_size;
+
     njs_log_level_t                 log_level;
 
 #define NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE   0
diff -r 62b475cce018 -r 581c321d4015 src/njs_function.c
--- a/src/njs_function.c	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs_function.c	Thu Nov 10 09:33:36 2022 -0800
@@ -464,7 +464,7 @@ njs_function_frame_alloc(njs_vm_t *vm, s
         spare_size = size + NJS_FRAME_SPARE_SIZE;
         spare_size = njs_align_size(spare_size, NJS_FRAME_SPARE_SIZE);
 
-        if (vm->stack_size + spare_size > NJS_MAX_STACK_SIZE) {
+        if (spare_size > vm->spare_stack_size) {
             njs_range_error(vm, "Maximum call stack size exceeded");
             return NULL;
         }
@@ -476,7 +476,7 @@ njs_function_frame_alloc(njs_vm_t *vm, s
         }
 
         chunk_size = spare_size;
-        vm->stack_size += spare_size;
+        vm->spare_stack_size -= spare_size;
     }
 
     njs_memzero(frame, sizeof(njs_native_frame_t));
@@ -702,7 +702,7 @@ njs_function_frame_free(njs_vm_t *vm, nj
         /* GC: free frame->local, etc. */
 
         if (native->size != 0) {
-            vm->stack_size -= native->size;
+            vm->spare_stack_size += native->size;
             njs_mp_free(vm->mem_pool, native);
         }
 
diff -r 62b475cce018 -r 581c321d4015 src/njs_shell.c
--- a/src/njs_shell.c	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs_shell.c	Thu Nov 10 09:33:36 2022 -0800
@@ -39,6 +39,7 @@ typedef struct {
     uint8_t                 opcode_debug;
     uint8_t                 generator_debug;
     int                     exit_code;
+    int                     stack_size;
 
     char                    *file;
     char                    *command;
@@ -292,6 +293,10 @@ main(int argc, char **argv)
     vm_options.ast = opts.ast;
     vm_options.unhandled_rejection = opts.unhandled_rejection;
 
+    if (opts.stack_size != 0) {
+        vm_options.max_stack_size = opts.stack_size;
+    }
+
 #ifdef NJS_HAVE_READLINE
 
     if (opts.interactive) {
@@ -343,15 +348,16 @@ njs_options_parse(njs_opts_t *opts, int 
         "  -a                print AST.\n"
         "  -c                specify the command to execute.\n"
         "  -d                print disassembled code.\n"
-        "  -e                set failure exit code.\n"
+        "  -e <code>         set failure exit code.\n"
         "  -f                disabled denormals mode.\n"
 #ifdef NJS_DEBUG_GENERATOR
         "  -g                enable generator debug.\n"
 #endif
+        "  -j <size>         set the maximum stack size in bytes.\n"
 #ifdef NJS_DEBUG_OPCODE
         "  -o                enable opcode debug.\n"
 #endif
-        "  -p                set path prefix for modules.\n"
+        "  -p <path>         set path prefix for modules.\n"
         "  -q                disable interactive introduction prompt.\n"
         "  -r                ignore unhandled promise rejection.\n"
         "  -s                sandbox mode.\n"
@@ -432,6 +438,14 @@ njs_options_parse(njs_opts_t *opts, int 
             opts->generator_debug = 1;
             break;
 #endif
+        case 'j':
+            if (++i < argc) {
+                opts->stack_size = atoi(argv[i]);
+                break;
+            }
+
+            njs_stderror("option \"-j\" requires argument\n");
+            return NJS_ERROR;
 
 #ifdef NJS_DEBUG_OPCODE
         case 'o':
diff -r 62b475cce018 -r 581c321d4015 src/njs_vm.c
--- a/src/njs_vm.c	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs_vm.c	Thu Nov 10 09:33:36 2022 -0800
@@ -26,6 +26,7 @@ njs_vm_opt_init(njs_vm_opt_t *options)
     njs_memzero(options, sizeof(njs_vm_opt_t));
 
     options->log_level = NJS_LOG_LEVEL_INFO;
+    options->max_stack_size = NJS_MAX_STACK_SIZE;
 }
 
 
@@ -71,6 +72,8 @@ njs_vm_create(njs_vm_opt_t *options)
 
     vm->external = options->external;
 
+    vm->spare_stack_size = options->max_stack_size;
+
     vm->trace.level = NJS_LEVEL_TRACE;
     vm->trace.size = 2048;
     vm->trace.data = vm;
diff -r 62b475cce018 -r 581c321d4015 src/njs_vm.h
--- a/src/njs_vm.h	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs_vm.h	Thu Nov 10 09:33:36 2022 -0800
@@ -8,7 +8,7 @@
 #define _NJS_VM_H_INCLUDED_
 
 
-#define NJS_MAX_STACK_SIZE       (256 * 1024)
+#define NJS_MAX_STACK_SIZE       (64 * 1024)
 
 
 typedef struct njs_frame_s            njs_frame_t;
@@ -160,7 +160,7 @@ struct njs_vm_s {
     njs_mp_t                 *mem_pool;
 
     u_char                   *start;
-    size_t                   stack_size;
+    size_t                   spare_stack_size;
 
     njs_vm_shared_t          *shared;
 
diff -r 62b475cce018 -r 581c321d4015 src/njs_vmcode.c
--- a/src/njs_vmcode.c	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/njs_vmcode.c	Thu Nov 10 09:33:36 2022 -0800
@@ -1837,7 +1837,7 @@ error:
         njs_vm_scopes_restore(vm, native, previous);
 
         if (native->size != 0) {
-            vm->stack_size -= native->size;
+            vm->spare_stack_size += native->size;
             njs_mp_free(vm->mem_pool, native);
         }
 
diff -r 62b475cce018 -r 581c321d4015 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Mon Nov 07 14:22:41 2022 -0800
+++ b/src/test/njs_unit_test.c	Thu Nov 10 09:33:36 2022 -0800
@@ -23218,7 +23218,7 @@ njs_vm_value_test(njs_unit_test_t unused
 
     for (i = 0; i < njs_nitems(tests); i++) {
 
-        memset(&options, 0, sizeof(njs_vm_opt_t));
+        njs_vm_opt_init(&options);
         options.init = 1;
 
         vm = njs_vm_create(&options);



More information about the nginx-devel mailing list