details: http://hg.nginx.org/njs/rev/6d0d4a92fa02 branches: changeset: 269:6d0d4a92fa02 user: Igor Sysoev <i...@sysoev.ru> date: Thu Dec 01 18:56:35 2016 +0300 description: Maximum call stack size is limited by 16M.
diffstat: njs/njs_function.c | 20 +++++++++++++++----- njs/njs_function.h | 14 ++++---------- njs/njs_vm.c | 6 ++++-- njs/njs_vm.h | 3 +++ njs/njscript.c | 2 +- njs/test/njs_unit_test.c | 3 +++ 6 files changed, 30 insertions(+), 18 deletions(-) diffs (172 lines): diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/njs_function.c --- a/njs/njs_function.c Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/njs_function.c Thu Dec 01 18:56:35 2016 +0300 @@ -16,6 +16,7 @@ #include <nxt_mem_cache_pool.h> #include <njscript.h> #include <njs_vm.h> +#include <njs_string.h> #include <njs_object.h> #include <njs_array.h> #include <njs_function.h> @@ -199,35 +200,44 @@ njs_function_frame(njs_vm_t *vm, njs_fun } +static const njs_value_t njs_exception_stack_size_exceeded = + njs_long_string("RangeError: Maximum call stack size exceeded"); + + nxt_noinline njs_native_frame_t * njs_function_frame_alloc(njs_vm_t *vm, size_t size) { - size_t spare_size; - uint8_t first; + size_t spare_size, chunk_size; njs_native_frame_t *frame; spare_size = vm->frame->free_size; if (nxt_fast_path(size <= spare_size)) { frame = (njs_native_frame_t *) vm->frame->free; - first = 0; + chunk_size = 0; } else { spare_size = size + NJS_FRAME_SPARE_SIZE; spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE); + if (vm->stack_size + spare_size > NJS_MAX_STACK_SIZE) { + vm->exception = &njs_exception_stack_size_exceeded; + return NULL; + } + frame = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), spare_size); if (nxt_slow_path(frame == NULL)) { return NULL; } - first = 1; + chunk_size = spare_size; + vm->stack_size += spare_size; } memset(frame, 0, sizeof(njs_native_frame_t)); - frame->first = first; + frame->size = chunk_size; frame->free_size = spare_size - size; frame->free = (u_char *) frame + size; diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/njs_function.h --- a/njs/njs_function.h Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/njs_function.h Thu Dec 01 18:56:35 2016 +0300 @@ -89,30 +89,24 @@ struct njs_native_frame_s { njs_exception_t exception; + uint32_t size; uint32_t free_size; uint32_t nargs; /* Function is called as constructor with "new" keyword. */ uint8_t ctor; /* 1 bit */ - /* - * The first frame in chunk. - * 7 bits are just to possibly initialize first and skip - * fields with one operation. - */ - uint8_t first:7; /* 1 bit */ - /* Skip the Function.call() and Function.apply() methods frames. */ - uint8_t skip:1; /* 1 bit */ + uint8_t skip; /* 1 bit */ /* A number of trap tries, it can be no more than three. */ - uint8_t trap_tries:2; /* 2 bits */ + uint8_t trap_tries; /* 2 bits */ /* * The first operand in trap is reference to original value, * it is used to increment or decrement this value. */ - uint8_t trap_reference:1; /* 1 bit */ + uint8_t trap_reference; /* 1 bit */ }; diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/njs_vm.c --- a/njs/njs_vm.c Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/njs_vm.c Thu Dec 01 18:56:35 2016 +0300 @@ -277,7 +277,8 @@ start: vm->scopes[NJS_SCOPE_LOCAL] = frame->prev_local; vm->scopes[NJS_SCOPE_ARGUMENTS] = frame->prev_arguments; - if (frame->native.first) { + if (frame->native.size != 0) { + vm->stack_size -= frame->native.size; nxt_mem_cache_free(vm->mem_cache_pool, frame); } } @@ -2673,7 +2674,8 @@ njs_function_frame_free(njs_vm_t *vm, nj /* GC: free frame->local, etc. */ - if (frame->first) { + if (frame->size != 0) { + vm->stack_size -= frame->size; nxt_mem_cache_free(vm->mem_cache_pool, frame); } diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/njs_vm.h --- a/njs/njs_vm.h Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/njs_vm.h Thu Dec 01 18:56:35 2016 +0300 @@ -12,6 +12,8 @@ #include <nxt_regex.h> +#define NJS_MAX_STACK_SIZE (16 * 1024 * 1024) + /* * Negative return values handled by nJSVM interpreter as special events. * The values must be in range from -1 to -11, because -12 is minimal jump @@ -829,6 +831,7 @@ struct njs_vm_s { njs_value_t *global_scope; size_t scope_size; + size_t stack_size; njs_vm_shared_t *shared; njs_parser_t *parser; diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/njscript.c --- a/njs/njscript.c Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/njscript.c Thu Dec 01 18:56:35 2016 +0300 @@ -324,12 +324,12 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache nvm->frame = &frame->native; + frame->native.size = size; frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size); values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE; frame->native.free = values + scope_size; - frame->native.first = 1; nvm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values; memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, diff -r 86c35adbd3f9 -r 6d0d4a92fa02 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Nov 30 14:53:15 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Dec 01 18:56:35 2016 +0300 @@ -3759,6 +3759,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("return"), nxt_string("SyntaxError: Illegal return statement in 1") }, + { nxt_string("function f() { return f() } f()"), + nxt_string("RangeError: Maximum call stack size exceeded") }, + { nxt_string("function () { } f()"), nxt_string("SyntaxError: Unexpected token \"(\" in 1") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel