From 3995aba47f6ed1c91a6114ef950f3f65014dcd28 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 20 Feb 2018 19:12:55 +0300 Subject: [PATCH] Fixed the names of global functions in backtraces. Previously, they were reported as 'native (native)'. --- njs/njs_builtin.c | 92 ++++++++++++++++------------ njs/njs_extern.c | 102 ++++++++++++++++++++++++++++++++ njs/njs_extern.h | 4 ++ njs/njs_function.c | 2 +- njs/njs_module.c | 7 +++ njs/njs_module.h | 1 + njs/njs_number.c | 28 +++++++++ njs/njs_number.h | 5 ++ njs/njs_string.c | 35 +++++++++++ njs/njs_string.h | 6 ++ njs/njs_vm.c | 12 +++- njs/test/njs_expect_test.exp | 6 ++ njs/test/njs_interactive_test.c | 10 ++++ 13 files changed, 268 insertions(+), 42 deletions(-) diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c index 314adbcf..d4e6267a 100644 --- a/njs/njs_builtin.c +++ b/njs/njs_builtin.c @@ -102,6 +102,38 @@ const njs_object_init_t *njs_constructor_init[] = { }; +const njs_object_init_t *njs_function_init[] = { + &njs_eval_function_init, + &njs_to_string_function_init, + &njs_is_nan_function_init, + &njs_is_finite_function_init, + &njs_parse_int_function_init, + &njs_parse_float_function_init, + &njs_encode_uri_function_init, + &njs_encode_uri_component_function_init, + &njs_decode_uri_function_init, + &njs_decode_uri_component_function_init, + &njs_require_function_init +}; + + +const njs_function_init_t njs_native_functions[] = { + /* SunC does not allow empty array initialization. */ + { njs_eval_function, { 0 } }, + { njs_object_prototype_to_string, { 0 } }, + { njs_number_global_is_nan, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, + { njs_number_is_finite, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, + { njs_number_parse_int, + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } }, + { njs_number_parse_float, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_encode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_decode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_decode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } }, +}; + + static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) @@ -190,36 +222,6 @@ njs_builtin_objects_create(njs_vm_t *vm) { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, }; - static const njs_object_init_t *function_init[] = { - &njs_eval_function_init, /* eval */ - NULL, /* toString */ - NULL, /* isNaN */ - NULL, /* isFinite */ - NULL, /* parseInt */ - NULL, /* parseFloat */ - NULL, /* encodeURI */ - NULL, /* encodeURIComponent */ - NULL, /* decodeURI */ - NULL, /* decodeURIComponent */ - NULL, /* require */ - }; - - static const njs_function_init_t native_functions[] = { - /* SunC does not allow empty array initialization. */ - { njs_eval_function, { 0 } }, - { njs_object_prototype_to_string, { 0 } }, - { njs_number_global_is_nan, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_number_is_finite, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_number_parse_int, - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } }, - { njs_number_parse_float, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_encode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_decode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_string_decode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - }; - static const njs_object_prop_t null_proto_property = { .type = NJS_WHITEOUT, .name = njs_string("__proto__"), @@ -293,10 +295,10 @@ njs_builtin_objects_create(njs_vm_t *vm) functions = vm->shared->functions; for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { - if (function_init[i] != NULL) { + if (njs_function_init[i]->items != 0) { ret = njs_object_hash_create(vm, &functions[i].object.shared_hash, - function_init[i]->properties, - function_init[i]->items); + njs_function_init[i]->properties, + njs_function_init[i]->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -306,12 +308,12 @@ njs_builtin_objects_create(njs_vm_t *vm) functions[i].object.extensible = 1; functions[i].native = 1; functions[i].args_offset = 1; - functions[i].u.native = native_functions[i].native; - functions[i].args_types[0] = native_functions[i].args_types[0]; - functions[i].args_types[1] = native_functions[i].args_types[1]; - functions[i].args_types[2] = native_functions[i].args_types[2]; - functions[i].args_types[3] = native_functions[i].args_types[3]; - functions[i].args_types[4] = native_functions[i].args_types[4]; + functions[i].u.native = njs_native_functions[i].native; + functions[i].args_types[0] = njs_native_functions[i].args_types[0]; + functions[i].args_types[1] = njs_native_functions[i].args_types[1]; + functions[i].args_types[2] = njs_native_functions[i].args_types[2]; + functions[i].args_types[3] = njs_native_functions[i].args_types[3]; + functions[i].args_types[4] = njs_native_functions[i].args_types[4]; } prototypes = vm->shared->prototypes; @@ -1022,6 +1024,18 @@ njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, } } + for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { + if (njs_function_init[i] == NULL) { + continue; + } + + if (function->u.native == njs_native_functions[i].native) { + *name = njs_function_init[i]->name; + + return NXT_OK; + } + } + nxt_lvlhsh_each_init(&lhe, &njs_modules_hash_proto); for ( ;; ) { diff --git a/njs/njs_extern.c b/njs/njs_extern.c index df2e28bf..b1fac6fc 100644 --- a/njs/njs_extern.c +++ b/njs/njs_extern.c @@ -22,6 +22,15 @@ #include #include #include +#include + + +typedef struct njs_extern_part_s njs_extern_part_t; + +struct njs_extern_part_s { + njs_extern_part_t *next; + nxt_str_t str; +}; static nxt_int_t @@ -242,3 +251,96 @@ njs_parser_external(njs_vm_t *vm, njs_parser_t *parser) return NULL; } + + +static nxt_int_t +njs_external_match(njs_vm_t *vm, njs_function_native_t func, njs_extern_t *ext, + nxt_str_t *name, njs_extern_part_t *head, njs_extern_part_t *ppart) +{ + char *buf, *p; + size_t len; + nxt_int_t ret; + njs_extern_t *prop; + njs_extern_part_t part, *pr; + nxt_lvlhsh_each_t lhe; + + ppart->next = ∂ + + nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto); + + for ( ;; ) { + prop = nxt_lvlhsh_each(&ext->hash, &lhe); + if (prop == NULL) { + break; + } + + part.next = NULL; + part.str = prop->name; + + if (prop->function && prop->function->u.native == func) { + goto found; + } + + ret = njs_external_match(vm, func, prop, name, head, &part); + if (ret != NXT_DECLINED) { + return ret; + } + } + + return NXT_DECLINED; + +found: + + len = 0; + + for (pr = head; pr != NULL; pr = pr->next) { + len += pr->str.length + sizeof(".") - 1; + } + + buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (buf == NULL) { + return NXT_ERROR; + } + + p = buf; + + for (pr = head; pr != NULL; pr = pr->next) { + p += snprintf(p, buf + len - p, "%.*s.", (int) pr->str.length, + pr->str.start); + } + + name->start = (u_char *) buf; + name->length = len; + + return NXT_OK; +} + + +nxt_int_t +njs_external_match_native_function(njs_vm_t *vm, njs_function_native_t func, + nxt_str_t *name) +{ + nxt_int_t ret; + njs_extern_t *ext; + njs_extern_part_t part; + nxt_lvlhsh_each_t lhe; + + nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto); + + for ( ;; ) { + ext = nxt_lvlhsh_each(&vm->external_prototypes_hash, &lhe); + if (ext == NULL) { + break; + } + + part.next = NULL; + part.str = ext->name; + + ret = njs_external_match(vm, func, ext, name, &part, &part); + if (ret != NXT_DECLINED) { + return ret; + } + } + + return NXT_DECLINED; +} diff --git a/njs/njs_extern.h b/njs/njs_extern.h index 2ef45e82..4db49dbc 100644 --- a/njs/njs_extern.h +++ b/njs/njs_extern.h @@ -38,6 +38,10 @@ typedef struct { } njs_extern_value_t; +nxt_int_t njs_external_match_native_function(njs_vm_t *vm, + njs_function_native_t func, nxt_str_t *name); + + extern const nxt_lvlhsh_proto_t njs_extern_hash_proto; extern const nxt_lvlhsh_proto_t njs_extern_value_hash_proto; diff --git a/njs/njs_function.c b/njs/njs_function.c index 2f17e5d6..6e8cce11 100644 --- a/njs/njs_function.c +++ b/njs/njs_function.c @@ -723,7 +723,7 @@ static const njs_object_prop_t njs_eval_function_properties[] = const njs_object_init_t njs_eval_function_init = { - nxt_string("Function"), + nxt_string("eval"), njs_eval_function_properties, nxt_nitems(njs_eval_function_properties), }; diff --git a/njs/njs_module.c b/njs/njs_module.c index b44c7430..83a77cb8 100644 --- a/njs/njs_module.c +++ b/njs/njs_module.c @@ -83,3 +83,10 @@ njs_ret_t njs_module_require(njs_vm_t *vm, njs_value_t *args, return NJS_ERROR; } + + +const njs_object_init_t njs_require_function_init = { + nxt_string("require"), + NULL, + 0, +}; diff --git a/njs/njs_module.h b/njs/njs_module.h index 441e2a7e..58091084 100644 --- a/njs/njs_module.h +++ b/njs/njs_module.h @@ -18,5 +18,6 @@ njs_ret_t njs_module_require(njs_vm_t *vm, njs_value_t *args, extern const nxt_lvlhsh_proto_t njs_modules_hash_proto; +extern const njs_object_init_t njs_require_function_init; #endif /* _NJS_MODULE_H_INCLUDED_ */ diff --git a/njs/njs_number.c b/njs/njs_number.c index d468dbd5..433aee86 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -896,3 +896,31 @@ njs_number_to_integer(double num) return (uint32_t) i64; } + + +const njs_object_init_t njs_is_nan_function_init = { + nxt_string("isNaN"), + NULL, + 0, +}; + + +const njs_object_init_t njs_is_finite_function_init = { + nxt_string("isFinite"), + NULL, + 0, +}; + + +const njs_object_init_t njs_parse_int_function_init = { + nxt_string("parseInt"), + NULL, + 0, +}; + + +const njs_object_init_t njs_parse_float_function_init = { + nxt_string("parseFloat"), + NULL, + 0, +}; diff --git a/njs/njs_number.h b/njs/njs_number.h index 2c60fd99..33f59fa2 100644 --- a/njs/njs_number.h +++ b/njs/njs_number.h @@ -35,5 +35,10 @@ nxt_noinline uint32_t njs_number_to_integer(double num); extern const njs_object_init_t njs_number_constructor_init; extern const njs_object_init_t njs_number_prototype_init; +extern const njs_object_init_t njs_is_nan_function_init; +extern const njs_object_init_t njs_is_finite_function_init; +extern const njs_object_init_t njs_parse_int_function_init; +extern const njs_object_init_t njs_parse_float_function_init; + #endif /* _NJS_NUMBER_H_INCLUDED_ */ diff --git a/njs/njs_string.c b/njs/njs_string.c index c6ff1af5..b1690ac5 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -3791,3 +3791,38 @@ njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src) return (njs_index_t) value; } + + +const njs_object_init_t njs_to_string_function_init = { + nxt_string("toString"), + NULL, + 0, +}; + + +const njs_object_init_t njs_encode_uri_function_init = { + nxt_string("encodeURI"), + NULL, + 0, +}; + + +const njs_object_init_t njs_encode_uri_component_function_init = { + nxt_string("encodeURIComponent"), + NULL, + 0, +}; + + +const njs_object_init_t njs_decode_uri_function_init = { + nxt_string("decodeURI"), + NULL, + 0, +}; + + +const njs_object_init_t njs_decode_uri_component_function_init = { + nxt_string("decodeURIComponent"), + NULL, + 0, +}; diff --git a/njs/njs_string.h b/njs/njs_string.h index 4ebfe422..361b4504 100644 --- a/njs/njs_string.h +++ b/njs/njs_string.h @@ -158,5 +158,11 @@ njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser, extern const njs_object_init_t njs_string_constructor_init; extern const njs_object_init_t njs_string_prototype_init; +extern const njs_object_init_t njs_to_string_function_init; +extern const njs_object_init_t njs_encode_uri_function_init; +extern const njs_object_init_t njs_encode_uri_component_function_init; +extern const njs_object_init_t njs_decode_uri_function_init; +extern const njs_object_init_t njs_decode_uri_component_function_init; + #endif /* _NJS_STRING_H_INCLUDED_ */ diff --git a/njs/njs_vm.c b/njs/njs_vm.c index bfb35dd1..2c742bfd 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -3744,10 +3744,18 @@ njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame) if (function->native) { ret = njs_builtin_match_native_function(vm, function, &be->name); - if (ret != NXT_OK) { - be->name = entry_native; + if (ret == NXT_OK) { + return NXT_OK; } + ret = njs_external_match_native_function(vm, function->u.native, + &be->name); + if (ret == NXT_OK) { + return NXT_OK; + } + + be->name = entry_native; + return NXT_OK; } diff --git a/njs/test/njs_expect_test.exp b/njs/test/njs_expect_test.exp index 727d451a..2d5c2a62 100644 --- a/njs/test/njs_expect_test.exp +++ b/njs/test/njs_expect_test.exp @@ -171,6 +171,12 @@ njs_test { "console.ll()\r\nTypeError: cannot find property 'll' of an external object"} } +# Backtraces for external objects +njs_test { + {"console.log(console)\r\n" + "console.log(console)\r\nTypeError:*at console.log (native)"} +} + # Exception in njs_vm_retval_to_ext_string() njs_test { {"var o = { toString: function() { return [1] } }\r\n" diff --git a/njs/test/njs_interactive_test.c b/njs/test/njs_interactive_test.c index 8bf3c7cb..b09bccac 100644 --- a/njs/test/njs_interactive_test.c +++ b/njs/test/njs_interactive_test.c @@ -162,6 +162,16 @@ static njs_interactive_test_t njs_test[] = " at Math.log (native)\n" " at main (native)\n") }, + { nxt_string("eval()" ENTER), + nxt_string("InternalError: Not implemented\n" + " at eval (native)\n" + " at main (native)\n") }, + + { nxt_string("require()" ENTER), + nxt_string("TypeError: missing path\n" + " at require (native)\n" + " at main (native)\n") }, + { nxt_string("function f(o) {function f_in(o) {return o.a.a};" " return f_in(o)}; f({})" ENTER), nxt_string("TypeError: cannot get property 'a' of undefined\n" -- 2.47.3