[njs] Maximum call stack size is limited by 16M.
Igor Sysoev
igor at sysoev.ru
Thu Dec 1 16:49:23 UTC 2016
details: http://hg.nginx.org/njs/rev/6d0d4a92fa02
branches:
changeset: 269:6d0d4a92fa02
user: Igor Sysoev <igor at 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") },
More information about the nginx-devel
mailing list