Dmitry Volyntsev
November 29, 2019 09:30AM
details: https://hg.nginx.org/njs/rev/e20023dd991d
branches:
changeset: 1270:e20023dd991d
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Fri Nov 29 17:11:11 2019 +0300
description:
Making backtrace a property of a thrown exception.

diffstat:

src/njs.h | 6 +-
src/njs_error.c | 172 ++++++++++++++++++++++--
src/njs_error.h | 2 +
src/njs_json.c | 4 -
src/njs_object_hash.h | 9 +
src/njs_shell.c | 22 +-
src/njs_vm.c | 276 +++++++++++++++++----------------------
src/njs_vm.h | 7 +-
src/njs_vmcode.c | 14 +-
src/test/njs_interactive_test.c | 5 +-
test/njs_expect_test.exp | 21 ++-
11 files changed, 332 insertions(+), 206 deletions(-)

diffs (837 lines):

diff -r 5bbbc4361799 -r e20023dd991d src/njs.h
--- a/src/njs.h Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs.h Fri Nov 29 17:11:11 2019 +0300
@@ -258,19 +258,19 @@ NJS_EXPORT njs_int_t njs_vm_value_string
NJS_EXPORT u_char *njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value,
uint32_t size);
NJS_EXPORT njs_int_t njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval,
- const njs_value_t *value, uintptr_t *next);
+ njs_value_t *value, uintptr_t *next);

/*
* Converts a value to string.
*/
NJS_EXPORT njs_int_t njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst,
- const njs_value_t *src);
+ njs_value_t *src);

/*
* Calls njs_vm_value_to_string(), if exception was thrown adds backtrace.
*/
NJS_EXPORT njs_int_t njs_vm_value_string(njs_vm_t *vm, njs_str_t *dst,
- const njs_value_t *src);
+ njs_value_t *src);
NJS_EXPORT njs_int_t njs_vm_retval_string(njs_vm_t *vm, njs_str_t *dst);

NJS_EXPORT njs_int_t njs_vm_value_dump(njs_vm_t *vm, njs_str_t *dst,
diff -r 5bbbc4361799 -r e20023dd991d src/njs_error.c
--- a/src/njs_error.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_error.c Fri Nov 29 17:11:11 2019 +0300
@@ -10,6 +10,7 @@

static const njs_value_t njs_error_message_string = njs_string("message");
static const njs_value_t njs_error_name_string = njs_string("name");
+static const njs_value_t njs_error_stack_string = njs_string("stack");


void
@@ -59,6 +60,127 @@ njs_error_fmt_new(njs_vm_t *vm, njs_valu
}


+static njs_int_t
+njs_error_stack_new(njs_vm_t *vm, njs_object_t *error, njs_value_t *retval)
+{
+ njs_int_t ret;
+ njs_str_t string;
+ njs_arr_t *stack;
+ njs_value_t value;
+ njs_native_frame_t *frame;
+
+ njs_set_object(&value, error);
+
+ ret = njs_error_to_string(vm, retval, &value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ stack = njs_arr_create(vm->mem_pool, 4, sizeof(njs_backtrace_entry_t));
+ if (njs_slow_path(stack == NULL)) {
+ return NJS_ERROR;
+ }
+
+ frame = vm->top_frame;
+
+ for ( ;; ) {
+ if (njs_vm_add_backtrace_entry(vm, stack, frame) != NJS_OK) {
+ break;
+ }
+
+ frame = frame->previous;
+
+ if (frame == NULL) {
+ break;
+ }
+ }
+
+ njs_string_get(retval, &string);
+
+ ret = njs_vm_backtrace_to_string(vm, stack, &string);
+
+ njs_arr_destroy(stack);
+
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ return njs_string_set(vm, retval, string.start, string.length);
+}
+
+
+njs_int_t
+njs_error_stack_attach(njs_vm_t *vm, njs_value_t *value)
+{
+ njs_int_t ret;
+ njs_object_t *error;
+ njs_object_prop_t *prop;
+ njs_lvlhsh_query_t lhq;
+
+ if (njs_slow_path(!njs_is_error(value))) {
+ return NJS_DECLINED;
+ }
+
+ if (vm->debug == NULL || vm->start == NULL) {
+ return NJS_OK;
+ }
+
+ error = njs_object(value);
+
+ lhq.replace = 0;
+ lhq.pool = vm->mem_pool;
+ lhq.proto = &njs_object_hash_proto;
+
+ lhq.key = njs_str_value("stack");
+ lhq.key_hash = NJS_STACK_HASH;
+
+ prop = njs_object_prop_alloc(vm, &njs_error_stack_string,
+ &njs_value_undefined, 1);
+ if (njs_slow_path(prop == NULL)) {
+ return NJS_ERROR;
+ }
+
+ prop->enumerable = 0;
+
+ ret = njs_error_stack_new(vm, error, &prop->value);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ njs_internal_error(vm, "njs_error_stack_new() failed");
+ return NJS_ERROR;
+ }
+
+ if (ret == NJS_OK) {
+ lhq.value = prop;
+
+ ret = njs_lvlhsh_insert(&error->hash, &lhq);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ njs_internal_error(vm, "lvlhsh insert failed");
+ return NJS_ERROR;
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+njs_int_t
+njs_error_stack(njs_vm_t *vm, njs_value_t *value, njs_value_t *stack)
+{
+ njs_int_t ret;
+
+ ret = njs_value_property(vm, value, njs_value_arg(&njs_error_stack_string),
+ stack);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (!njs_is_string(stack)) {
+ return NJS_DECLINED;
+ }
+
+ return NJS_OK;
+}
+
+
njs_object_t *
njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name,
const njs_value_t *message)
@@ -83,11 +205,11 @@ njs_error_alloc(njs_vm_t *vm, njs_object

lhq.replace = 0;
lhq.pool = vm->mem_pool;
+ lhq.proto = &njs_object_hash_proto;

if (name != NULL) {
lhq.key = njs_str_value("name");
lhq.key_hash = NJS_NAME_HASH;
- lhq.proto = &njs_object_hash_proto;

prop = njs_object_prop_alloc(vm, &njs_error_name_string, name, 1);
if (njs_slow_path(prop == NULL)) {
@@ -106,7 +228,6 @@ njs_error_alloc(njs_vm_t *vm, njs_object
if (message!= NULL) {
lhq.key = njs_str_value("message");
lhq.key_hash = NJS_MESSAGE_HASH;
- lhq.proto = &njs_object_hash_proto;

prop = njs_object_prop_alloc(vm, &njs_error_message_string, message, 1);
if (njs_slow_path(prop == NULL)) {
@@ -605,20 +726,8 @@ njs_error_prototype_value_of(njs_vm_t *v


static njs_int_t
-njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- if (nargs < 1 || !njs_is_object(&args[0])) {
- njs_type_error(vm, "\"this\" argument is not an object");
- return NJS_ERROR;
- }
-
- return njs_error_to_string(vm, &vm->retval, &args[0]);
-}
-
-
-njs_int_t
-njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error)
+njs_error_to_string2(njs_vm_t *vm, njs_value_t *retval,
+ const njs_value_t *error, njs_bool_t want_stack)
{
size_t length;
u_char *p;
@@ -630,6 +739,17 @@ njs_error_to_string(njs_vm_t *vm, njs_va

static const njs_value_t default_name = njs_string("Error");

+ if (want_stack) {
+ ret = njs_error_stack(vm, njs_value_arg(error), retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (ret == NJS_OK) {
+ return NJS_OK;
+ }
+ }
+
njs_object_property_init(&lhq, &njs_string_name, NJS_NAME_HASH);

ret = njs_object_property(vm, error, &lhq, &value1);
@@ -708,6 +828,26 @@ njs_error_to_string(njs_vm_t *vm, njs_va
}


+static njs_int_t
+njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ if (nargs < 1 || !njs_is_object(&args[0])) {
+ njs_type_error(vm, "\"this\" argument is not an object");
+ return NJS_ERROR;
+ }
+
+ return njs_error_to_string2(vm, &vm->retval, &args[0], 0);
+}
+
+
+njs_int_t
+njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error)
+{
+ return njs_error_to_string2(vm, retval, error, 1);
+}
+
+
static const njs_object_prop_t njs_error_prototype_properties[] =
{
{
diff -r 5bbbc4361799 -r e20023dd991d src/njs_error.h
--- a/src/njs_error.h Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_error.h Fri Nov 29 17:11:11 2019 +0300
@@ -44,6 +44,8 @@ njs_object_t *njs_error_alloc(njs_vm_t *
const njs_value_t *name, const njs_value_t *message);
njs_int_t njs_error_to_string(njs_vm_t *vm, njs_value_t *retval,
const njs_value_t *error);
+njs_int_t njs_error_stack(njs_vm_t *vm, njs_value_t *value, njs_value_t *stack);
+njs_int_t njs_error_stack_attach(njs_vm_t *vm, njs_value_t *value);


extern const njs_object_type_init_t njs_error_type_init;
diff -r 5bbbc4361799 -r e20023dd991d src/njs_json.c
--- a/src/njs_json.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_json.c Fri Nov 29 17:11:11 2019 +0300
@@ -2144,10 +2144,6 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
njs_property_query_t pq;
njs_json_stringify_t *stringify, dump_stringify;

- if (njs_vm_backtrace(vm) != NULL) {
- goto exception;
- }
-
stringify = &dump_stringify;

stringify->vm = vm;
diff -r 5bbbc4361799 -r e20023dd991d src/njs_object_hash.h
--- a/src/njs_object_hash.h Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_object_hash.h Fri Nov 29 17:11:11 2019 +0300
@@ -411,6 +411,15 @@
's'), 'e'), 't')


+#define NJS_STACK_HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 's'), 't'), 'a'), 'c'), 'k')
+
+
#define NJS_STRING_HASH \
njs_djb_hash_add( \
njs_djb_hash_add( \
diff -r 5bbbc4361799 -r e20023dd991d src/njs_shell.c
--- a/src/njs_shell.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_shell.c Fri Nov 29 17:11:11 2019 +0300
@@ -722,19 +722,23 @@ njs_output(njs_opts_t *opts, njs_vm_t *v
{
njs_str_t out;

- if (!opts->silent) {
+ if (opts->silent) {
+ return;
+ }
+
+ if (ret == NJS_OK) {
if (njs_vm_retval_dump(vm, &out, 1) != NJS_OK) {
- out = njs_str_value("failed to get retval from VM");
- ret = NJS_ERROR;
+ njs_stderror("Shell:failed to get retval from VM\n");
+ return;
}

- if (ret != NJS_OK) {
- njs_stderror("%V\n", &out);
+ if (vm->options.accumulative) {
+ njs_printf("%V\n", &out);
+ }

- } else if (vm->options.accumulative) {
- njs_print(out.start, out.length);
- njs_printf("\n");
- }
+ } else {
+ njs_vm_retval_string(vm, &out);
+ njs_stderror("Thrown:\n%V\n", &out);
}
}

diff -r 5bbbc4361799 -r e20023dd991d src/njs_vm.c
--- a/src/njs_vm.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_vm.c Fri Nov 29 17:11:11 2019 +0300
@@ -153,10 +153,6 @@ njs_vm_compile(njs_vm_t *vm, u_char **st

parser->lexer = &lexer;

- if (vm->backtrace != NULL) {
- njs_arr_reset(vm->backtrace);
- }
-
njs_set_undefined(&vm->retval);

ret = njs_parser(vm, parser, prev);
@@ -471,10 +467,6 @@ njs_vm_post_event(njs_vm_t *vm, njs_vm_e
njs_int_t
njs_vm_run(njs_vm_t *vm)
{
- if (njs_slow_path(vm->backtrace != NULL)) {
- njs_arr_reset(vm->backtrace);
- }
-
return njs_vm_handle_events(vm);
}

@@ -648,120 +640,11 @@ njs_vm_memory_error(njs_vm_t *vm)
}


-njs_arr_t *
-njs_vm_backtrace(njs_vm_t *vm)
-{
- if (vm->backtrace != NULL && !njs_arr_is_empty(vm->backtrace)) {
- return vm->backtrace;
- }
-
- return NULL;
-}
-
-
-static njs_int_t
-njs_vm_backtrace_dump(njs_vm_t *vm, njs_str_t *dst, const njs_value_t *src)
+njs_int_t
+njs_vm_value_string(njs_vm_t *vm, njs_str_t *dst, njs_value_t *src)
{
- u_char *p, *start, *end;
- size_t len, count;
- njs_uint_t i;
- njs_arr_t *backtrace;
- njs_backtrace_entry_t *be, *prev;
-
- backtrace = njs_vm_backtrace(vm);
-
- len = dst->length + 1;
-
- count = 0;
- prev = NULL;
-
- be = backtrace->start;
-
- for (i = 0; i < backtrace->items; i++) {
- if (i != 0 && prev->name.start == be->name.start
- && prev->line == be->line)
- {
- count++;
-
- } else {
-
- if (count != 0) {
- len += njs_length(" repeats times\n")
- + NJS_INT_T_LEN;
- count = 0;
- }
-
- len += be->name.length + njs_length(" at ()\n");
-
- if (be->line != 0) {
- len += be->file.length + NJS_INT_T_LEN + 1;
-
- } else {
- len += njs_length("native");
- }
- }
-
- prev = be;
- be++;
- }
-
- p = njs_mp_alloc(vm->mem_pool, len);
- if (p == NULL) {
- njs_memory_error(vm);
- return NJS_ERROR;
- }
-
- start = p;
- end = start + len;
-
- p = njs_cpymem(p, dst->start, dst->length);
- *p++ = '\n';
-
- count = 0;
- prev = NULL;
-
- be = backtrace->start;
-
- for (i = 0; i < backtrace->items; i++) {
- if (i != 0 && prev->name.start == be->name.start
- && prev->line == be->line)
- {
- count++;
-
- } else {
- if (count != 0) {
- p = njs_sprintf(p, end, " repeats %uz times\n",
- count);
- count = 0;
- }
-
- p = njs_sprintf(p, end, " at %V ", &be->name);
-
- if (be->line != 0) {
- p = njs_sprintf(p, end, "(%V:%uD)\n", &be->file,
- be->line);
-
- } else {
- p = njs_sprintf(p, end, "(native)\n");
- }
- }
-
- prev = be;
- be++;
- }
-
- dst->start = start;
- dst->length = p - dst->start;
-
- return NJS_OK;
-}
-
-
-njs_int_t
-njs_vm_value_string(njs_vm_t *vm, njs_str_t *dst, const njs_value_t *src)
-{
- njs_int_t ret;
- njs_uint_t exception;
+ njs_int_t ret;
+ njs_uint_t exception;

if (njs_slow_path(src->type == NJS_NUMBER
&& njs_number(src) == 0
@@ -771,26 +654,17 @@ njs_vm_value_string(njs_vm_t *vm, njs_st
return NJS_OK;
}

- exception = 1;
+ exception = 0;

again:

ret = njs_vm_value_to_string(vm, dst, src);
-
if (njs_fast_path(ret == NJS_OK)) {
-
- if (njs_vm_backtrace(vm) != NULL) {
- ret = njs_vm_backtrace_dump(vm, dst, src);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
- }
-
return NJS_OK;
}

- if (exception) {
- exception = 0;
+ if (!exception) {
+ exception = 1;

/* value evaluation threw an exception. */

@@ -966,18 +840,18 @@ njs_vm_object_prop(njs_vm_t *vm, const n


njs_int_t
-njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst, const njs_value_t *src)
+njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst, njs_value_t *src)
{
u_char *start;
size_t size;
njs_int_t ret;
- njs_value_t value;
+ njs_value_t value, stack;

if (njs_slow_path(src == NULL)) {
return NJS_ERROR;
}

- if (njs_slow_path(njs_is_error(src))) {
+ if (njs_is_error(src)) {

/* MemoryError is a nonextensible internal error. */

@@ -987,6 +861,15 @@ njs_vm_value_to_string(njs_vm_t *vm, njs
njs_string_get(&njs_string_memory_error, dst);
return NJS_OK;
}
+
+ ret = njs_error_stack(vm, src, &stack);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (ret == NJS_OK) {
+ src = &stack;
+ }
}

value = *src;
@@ -1020,7 +903,7 @@ njs_vm_value_to_string(njs_vm_t *vm, njs

njs_int_t
njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval,
- const njs_value_t *value, uintptr_t *next)
+ njs_value_t *value, uintptr_t *next)
{
uintptr_t n;
njs_array_t *array;
@@ -1060,31 +943,19 @@ njs_vm_value_string_copy(njs_vm_t *vm, n


njs_int_t
-njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame)
+njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
+ njs_native_frame_t *native_frame)
{
njs_int_t ret;
- njs_arr_t *backtrace;
njs_uint_t i;
njs_function_t *function;
- njs_native_frame_t *native_frame;
njs_function_debug_t *debug_entry;
njs_function_lambda_t *lambda;
njs_backtrace_entry_t *be;

- if (njs_slow_path(vm->backtrace == NULL)) {
- backtrace = njs_arr_create(vm->mem_pool, 4,
- sizeof(njs_backtrace_entry_t));
- if (njs_slow_path(backtrace == NULL)) {
- return NJS_ERROR;
- }
-
- vm->backtrace = backtrace;
- }
-
- native_frame = &frame->native;
function = native_frame->function;

- be = njs_arr_add(vm->backtrace);
+ be = njs_arr_add(stack);
if (njs_slow_path(be == NULL)) {
return NJS_ERROR;
}
@@ -1143,6 +1014,107 @@ njs_vm_add_backtrace_entry(njs_vm_t *vm,
}


+njs_int_t
+njs_vm_backtrace_to_string(njs_vm_t *vm, njs_arr_t *backtrace, njs_str_t *dst)
+{
+ u_char *p, *start, *end;
+ size_t len, count;
+ njs_uint_t i;
+ njs_backtrace_entry_t *be, *prev;
+
+ if (backtrace->items == 0) {
+ return NJS_OK;
+ }
+
+ len = dst->length + 1;
+
+ count = 0;
+ prev = NULL;
+
+ be = backtrace->start;
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (i != 0 && prev->name.start == be->name.start
+ && prev->line == be->line)
+ {
+ count++;
+
+ } else {
+
+ if (count != 0) {
+ len += njs_length(" repeats times\n")
+ + NJS_INT_T_LEN;
+ count = 0;
+ }
+
+ len += be->name.length + njs_length(" at ()\n");
+
+ if (be->line != 0) {
+ len += be->file.length + NJS_INT_T_LEN + 1;
+
+ } else {
+ len += njs_length("native");
+ }
+ }
+
+ prev = be;
+ be++;
+ }
+
+ p = njs_mp_alloc(vm->mem_pool, len);
+ if (p == NULL) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ start = p;
+ end = start + len;
+
+ p = njs_cpymem(p, dst->start, dst->length);
+ *p++ = '\n';
+
+ count = 0;
+ prev = NULL;
+
+ be = backtrace->start;
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (i != 0 && prev->name.start == be->name.start
+ && prev->line == be->line)
+ {
+ count++;
+
+ } else {
+ if (count != 0) {
+ p = njs_sprintf(p, end, " repeats %uz times\n",
+ count);
+ count = 0;
+ }
+
+ p = njs_sprintf(p, end, " at %V ", &be->name);
+
+ if (be->line != 0) {
+ p = njs_sprintf(p, end, "(%V:%uD)\n", &be->file,
+ be->line);
+
+ } else {
+ p = njs_sprintf(p, end, "(native)\n");
+ }
+ }
+
+ prev = be;
+ be++;
+ }
+
+ dst->start = start;
+ dst->length = p - dst->start;
+
+ return NJS_OK;
+}
+
+
+
+
void *
njs_lvlhsh_alloc(void *data, size_t size)
{
diff -r 5bbbc4361799 -r e20023dd991d src/njs_vm.h
--- a/src/njs_vm.h Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_vm.h Fri Nov 29 17:11:11 2019 +0300
@@ -224,7 +224,6 @@ struct njs_vm_s {
njs_random_t random;

njs_arr_t *debug;
- njs_arr_t *backtrace;

/*
* njs_property_query() uses it to store reference to a temporary
@@ -272,14 +271,16 @@ struct njs_vm_shared_s {

void njs_vm_scopes_restore(njs_vm_t *vm, njs_frame_t *frame,
njs_native_frame_t *previous);
-njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame);
+njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
+ njs_native_frame_t *native_frame);
+njs_int_t njs_vm_backtrace_to_string(njs_vm_t *vm, njs_arr_t *stack,
+ njs_str_t *dst);

njs_int_t njs_builtin_objects_create(njs_vm_t *vm);
njs_int_t njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global);
njs_int_t njs_builtin_match_native_function(njs_vm_t *vm,
njs_function_native_t func, njs_str_t *name);

-njs_arr_t *njs_vm_backtrace(njs_vm_t *vm);
njs_arr_t *njs_vm_completions(njs_vm_t *vm, njs_str_t *expression);

void *njs_lvlhsh_alloc(void *data, size_t size);
diff -r 5bbbc4361799 -r e20023dd991d src/njs_vmcode.c
--- a/src/njs_vmcode.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/njs_vmcode.c Fri Nov 29 17:11:11 2019 +0300
@@ -898,6 +898,10 @@ next:

error:

+ if (njs_is_error(&vm->retval)) {
+ (void) njs_error_stack_attach(vm, &vm->retval);
+ }
+
for ( ;; ) {
frame = (njs_frame_t *) vm->top_frame;

@@ -906,19 +910,9 @@ error:
if (catch != NULL) {
pc = catch;

- if (vm->backtrace != NULL) {
- njs_arr_reset(vm->backtrace);
- }
-
goto next;
}

- if (vm->debug != NULL
- && njs_vm_add_backtrace_entry(vm, frame) != NJS_OK)
- {
- break;
- }
-
previous = frame->native.previous;
if (previous == NULL) {
break;
diff -r 5bbbc4361799 -r e20023dd991d src/test/njs_interactive_test.c
--- a/src/test/njs_interactive_test.c Thu Nov 28 13:25:00 2019 +0300
+++ b/src/test/njs_interactive_test.c Fri Nov 29 17:11:11 2019 +0300
@@ -243,10 +243,7 @@ static njs_interactive_test_t njs_test[
" at main (native)\n") },

{ njs_str("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)" ENTER),
- njs_str("a\n"
- " at f (:1)\n"
- " repeats 2 times\n"
- " at main (native)\n") },
+ njs_str("a") },

/* Exception in njs_vm_retval_string() */

diff -r 5bbbc4361799 -r e20023dd991d test/njs_expect_test.exp
--- a/test/njs_expect_test.exp Thu Nov 28 13:25:00 2019 +0300
+++ b/test/njs_expect_test.exp Fri Nov 29 17:11:11 2019 +0300
@@ -258,7 +258,7 @@ njs_test {

njs_test {
{"console.ll()\r\n"
- "console.ll()\r\nTypeError: (intermediate value)\\\[\"ll\"] is not a function"}
+ "console.ll()\r\nThrown:\r\nTypeError: (intermediate value)\\\[\"ll\"] is not a function"}
}

njs_test {
@@ -280,7 +280,7 @@ njs_test {
# Backtraces for external objects
njs_test {
{"console.log(console.a.a)\r\n"
- "console.log(console.a.a)\r\nTypeError:*at print (native)"}
+ "console.log(console.a.a)\r\nThrown:\r\nTypeError:*at print (native)"}
}

# dumper
@@ -321,9 +321,9 @@ njs_test {
# Backtraces are reset between invocations
njs_test {
{"JSON.parse(Error())\r\n"
- "JSON.parse(Error())\r\nSyntaxError: Unexpected token at position 0*at JSON.parse (native)"}
+ "JSON.parse(Error())\r\nThrown:\r\nSyntaxError: Unexpected token at position 0*at JSON.parse (native)"}
{"JSON.parse(Error()\r\n"
- "JSON.parse(Error()\r\nSyntaxError: Unexpected token \"\" in shell:1"}
+ "JSON.parse(Error()\r\nThrown:\r\nSyntaxError: Unexpected token \"\" in shell:1"}
}

njs_test {
@@ -335,7 +335,18 @@ njs_test {

njs_test {
{"(function() { throw 'test' })()\r\n"
- "test\r\n at anonymous (shell:1)"}
+ "Thrown:\r\ntest"}
+}
+
+njs_test {
+ {"function f() { return ({}.a.a); }\r\n"
+ "undefined"}
+ {"var e; try {f()} catch (ee) {e = ee}\r\n"
+ "undefined"}
+ {"Object.keys(null)\r\n"
+ "Thrown:\r\nTypeError: cannot convert null argument to object"}
+ {"e\r\n"
+ "TypeError: cannot get property \"a\" of undefined*at f (shell:1)"}
}

# Non-ASCII characters
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[njs] Making backtrace a property of a thrown exception.

Dmitry Volyntsev 306 November 29, 2019 09:30AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 231
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready