#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>
}
+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;
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 */
};
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);
}
}
/* 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);
}
#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
njs_value_t *global_scope;
size_t scope_size;
+ size_t stack_size;
njs_vm_shared_t *shared;
njs_parser_t *parser;
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,
{ 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") },