#include <signal.h>
-typedef struct {
- enum {
- NJS_BUILTIN_TRAVERSE_KEYS,
- NJS_BUILTIN_TRAVERSE_MATCH,
- } type;
-
- njs_function_t *func;
-
- njs_flathsh_t keys;
- njs_str_t match;
-} njs_builtin_traverse_t;
-
-
typedef struct {
njs_str_t name;
int value;
}
-static njs_int_t
-njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data)
-{
- size_t len;
- u_char *p, *start, *end;
- njs_int_t ret, n;
- njs_str_t name;
- njs_bool_t symbol;
- njs_value_t key, *value, prop_name;
- njs_function_t *func, *target;
- njs_object_prop_t *prop;
- njs_flathsh_query_t fhq;
- njs_builtin_traverse_t *ctx;
- njs_traverse_t *path[NJS_TRAVERSE_MAX_DEPTH];
- u_char buf[256];
-
- ctx = data;
-
- if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) {
- prop = traverse->prop;
- func = ctx->func;
-
- if (njs_is_accessor_descriptor(prop)) {
- target = njs_prop_getter(prop);
-
- } else {
- value = njs_prop_value(prop);
- target = (njs_is_function(value) && njs_function(value)->native)
- ? njs_function(value)
- : NULL;
- }
-
- if (target == NULL
- || !njs_native_function_same(target, func))
- {
- return NJS_OK;
- }
- }
-
- if (traverse == NULL) {
- njs_type_error(vm, "njs_builtin_traverse() traverse arg is NULL");
- return NJS_ERROR;
- }
-
- n = 0;
-
- while (traverse != NULL) {
- path[n++] = traverse;
- traverse = traverse->parent;
- }
-
- n--;
-
- p = buf;
- end = buf + sizeof(buf);
-
- do {
- symbol = 0;
-
- ret = njs_atom_to_value(vm, &key, path[n]->atom_id);
- if (ret != NJS_OK) {
- return NJS_ERROR;
- }
-
- if (njs_slow_path(njs_is_symbol(&key))) {
- symbol = 1;
- key = *njs_symbol_description(&key);
- if (njs_is_undefined(&key)) {
- njs_set_empty_string(vm, &key);
- }
- }
-
- if (njs_slow_path(!njs_is_string(&key))) {
- /* Skipping special properties (e.g. array index properties). */
- return NJS_OK;
- }
-
- njs_string_get(vm, &key, &name);
-
- if (njs_slow_path((p + name.length + 3) > end)) {
- njs_type_error(vm, "njs_builtin_traverse() key is too long");
- return NJS_ERROR;
- }
-
- if (symbol) {
- *p++ = '[';
-
- } else if (p != buf) {
- *p++ = '.';
- }
-
- p = njs_cpymem(p, name.start, name.length);
-
- if (symbol) {
- *p++ = ']';
- }
-
- } while (n-- > 0);
-
- if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) {
- len = ctx->match.length;
- start = njs_mp_alloc(vm->mem_pool, len + (p - buf) + (len != 0));
- if (njs_slow_path(start == NULL)) {
- njs_memory_error(vm);
- return NJS_ERROR;
- }
-
- if (len != 0) {
- memcpy(start, ctx->match.start, len);
- start[len++] = '.';
- }
-
- memcpy(start + len, buf, p - buf);
- ctx->match.length = len + p - buf;
- ctx->match.start = start;
-
- return NJS_DONE;
- }
-
- /* NJS_BUILTIN_TRAVERSE_KEYS. */
-
- ret = njs_atom_string_create(vm, &prop_name, buf, p - buf);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- fhq.key_hash = prop_name.atom_id;
- fhq.replace = 1;
- fhq.pool = vm->mem_pool;
- fhq.proto = &njs_object_hash_proto;
-
- ret = njs_flathsh_unique_insert(&ctx->keys, &fhq);
- if (njs_slow_path(ret != NJS_OK)) {
- njs_internal_error(vm, "flathsh insert/replace failed");
- return NJS_ERROR;
- }
-
- prop = fhq.value;
-
- prop->type = NJS_PROPERTY;
- prop->enumerable = 0;
- prop->configurable = 0;
- prop->writable = 0;
- prop->u.value = njs_value_null;
-
- return NJS_OK;
-}
-
-
-typedef struct {
- njs_str_t name;
- njs_function_native_t native;
- uint8_t magic8;
-} njs_function_name_t;
-
-
-njs_int_t
-njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function,
- njs_str_t *name)
-{
- uint8_t magic8;
- njs_int_t ret;
- njs_arr_t **pprotos;
- njs_mod_t *module;
- njs_uint_t i, n;
- njs_value_t value, tag;
- njs_object_t object;
- njs_object_prop_t *prop;
- njs_flathsh_each_t lhe;
- njs_exotic_slots_t *slots;
- njs_function_name_t *fn;
- njs_function_native_t native;
- njs_builtin_traverse_t ctx;
-
- if (vm->functions_name_cache != NULL) {
- n = vm->functions_name_cache->items;
- fn = vm->functions_name_cache->start;
-
- magic8 = function->magic8;
- native = function->u.native;
-
- while (n != 0) {
- if (fn->native == native && fn->magic8 == magic8) {
- *name = fn->name;
- return NJS_OK;
- }
-
- fn++;
- n--;
- }
- }
-
- ctx.type = NJS_BUILTIN_TRAVERSE_MATCH;
- ctx.func = function;
-
- /* Global object. */
-
- ctx.match = njs_str_value("");
-
- ret = njs_object_traverse(vm, njs_object(&vm->global_value), &ctx,
- njs_builtin_traverse);
-
- if (ret == NJS_DONE) {
- goto found;
- }
-
- /* Constructor from built-in modules (not-mapped to global object). */
-
- for (i = NJS_OBJ_TYPE_HIDDEN_MIN; i < NJS_OBJ_TYPE_HIDDEN_MAX; i++) {
- njs_set_object(&value, &njs_vm_ctor(vm, i).object);
-
- ret = njs_value_property(vm, &value, NJS_ATOM_STRING_name, &tag);
- if (ret == NJS_OK && njs_is_string(&tag)) {
- njs_string_get(vm, &tag, &ctx.match);
- }
-
- ret = njs_object_traverse(vm, njs_object(&value), &ctx,
- njs_builtin_traverse);
-
- if (ret == NJS_DONE) {
- goto found;
- }
- }
-
- /* Modules. */
-
- njs_flathsh_each_init(&lhe, &njs_modules_hash_proto);
-
- for ( ;; ) {
- prop = (njs_object_prop_t *) njs_flathsh_each(&vm->modules_hash, &lhe);
- if (prop == NULL) {
- break;
- }
-
- module = prop->u.mod;
-
- if (njs_is_object(&module->value)
- && !njs_object(&module->value)->shared)
- {
- ctx.match = module->name;
-
- ret = njs_object_traverse(vm, njs_object(&module->value), &ctx,
- njs_builtin_traverse);
-
- if (ret == NJS_DONE) {
- goto found;
- }
- }
- }
-
- /* External prototypes (not mapped to global object). */
-
- ctx.match = njs_str_value("");
-
- for (i = 0; i< vm->protos->items; i++) {
- njs_memzero(&object, sizeof(njs_object_t));
-
- pprotos = njs_arr_item(vm->protos, i);
- slots = (*pprotos)->start;
-
- object.shared_hash = slots->external_shared_hash;
- object.slots = slots;
-
- njs_set_object(&value, &object);
-
- ret = njs_object_string_tag(vm, &value, &tag);
- if (ret == NJS_OK && njs_is_string(&tag)) {
- njs_string_get(vm, &tag, &ctx.match);
- }
-
- ret = njs_object_traverse(vm, njs_object(&value), &ctx,
- njs_builtin_traverse);
-
- if (ret == NJS_DONE) {
- goto found;
- }
- }
-
- return NJS_DECLINED;
-
-found:
-
- if (vm->functions_name_cache == NULL) {
- vm->functions_name_cache = njs_arr_create(vm->mem_pool, 4,
- sizeof(njs_function_name_t));
- if (njs_slow_path(vm->functions_name_cache == NULL)) {
- return NJS_ERROR;
- }
- }
-
- fn = njs_arr_add(vm->functions_name_cache);
- if (njs_slow_path(fn == NULL)) {
- njs_memory_error(vm);
- return NJS_ERROR;
- }
-
- fn->name = ctx.match;
- fn->native = function->u.native;
- fn->magic8 = function->magic8;
-
- *name = fn->name;
-
- return NJS_OK;
-}
-
-
static njs_int_t
njs_ext_dump(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused, njs_value_t *retval)
void
njs_error_stack_attach(njs_vm_t *vm, njs_value_t value)
{
- size_t count;
- uint32_t line, prev_line;
- njs_int_t ret;
- njs_str_t name, file, prev_name;
- njs_chb_t chain;
- njs_value_t *stackval;
- njs_vm_code_t *code;
- njs_function_t *function;
- njs_native_frame_t *frame;
+ size_t count;
+ uint32_t line, prev_line;
+ njs_int_t ret;
+ njs_str_t name, file, prev_name;
+ njs_chb_t chain;
+ njs_value_t *stackval, retval, fobj;
+ njs_vm_code_t *code;
+ njs_function_t *function;
+ njs_object_prop_t *prop;
+ njs_native_frame_t *frame;
+ njs_flathsh_query_t fhq;
if (njs_slow_path(!vm->options.backtrace
|| !njs_is_error(&value))
}
} else {
- ret = njs_builtin_match_native_function(vm, function, &name);
- if (ret != NJS_OK) {
- name = njs_entry_unknown;
+ name.length = 0;
+ fhq.key_hash = NJS_ATOM_STRING_name;
+
+ ret = njs_flathsh_unique_find(&function->object.hash, &fhq);
+ if (ret == NJS_OK) {
+ prop = fhq.value;
+
+ if (njs_is_string(njs_prop_value(prop))) {
+ njs_string_get(vm, njs_prop_value(prop), &name);
+ }
+ }
+
+ if (name.length == 0) {
+ njs_set_function(&fobj, function);
+
+ ret = njs_value_property(vm, &fobj, NJS_ATOM_STRING_name,
+ &retval);
+ if (ret != NJS_OK) {
+ continue;
+ }
+
+ if (njs_is_string(&retval)) {
+ njs_string_get(vm, &retval, &name);
+
+ if (name.length == 0) {
+ continue;
+ }
+
+ } else if (njs_is_symbol(&retval)) {
+ name = njs_str_value("<symbol>");
+
+ } else {
+ name = njs_entry_unknown;
+ }
}
}
#ifdef NJS_DEBUG_OPCODE
njs_str_t name;
+ njs_value_t fname, fobj;
if (vm->options.opcode_debug) {
+ name = njs_str_value("unmapped");
- ret = njs_builtin_match_native_function(vm, function, &name);
- if (ret != NJS_OK) {
- name = njs_str_value("unmapped");
+ njs_set_function(&fobj, function);
+
+ ret = njs_value_property(vm, &fobj, NJS_ATOM_STRING_name, &fname);
+ if (ret == NJS_OK && njs_is_string(&fname)) {
+ njs_string_get(vm, &fname, &name);
}
njs_printf("CALL NATIVE %V %P\n", &name, function->u.native);
njs_value_t global_value;
njs_arr_t *codes; /* of njs_vm_code_t */
- njs_arr_t *functions_name_cache;
njs_trace_t trace;
njs_random_t random;
void njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *frame);
njs_int_t njs_builtin_objects_create(njs_vm_t *vm);
-njs_int_t njs_builtin_match_native_function(njs_vm_t *vm,
- njs_function_t *function, njs_str_t *name);
void njs_disassemble(u_char *start, u_char *end, njs_int_t count,
njs_arr_t *lines);
{ "exception.stack",
njs_str("function f() { try { throw new Error('test') } catch (e) { return e.stack } } [f].map(v=>v())[0]"),
- njs_str("Error: test\n at f (:1)\n at anonymous (:1)\n at Array.prototype.map (native)\n at main (:1)\n"),
+ njs_str("Error: test\n at f (:1)\n at anonymous (:1)\n at map (native)\n at main (:1)\n"),
+ 100 },
+
+ { "exception.native.stack",
+ njs_str("function f() { try { 'str'.replace(/t/g,function(m) {return m.a.a}) } catch (e) { return e.stack } }; f()"),
+ njs_str("TypeError: cannot get property \"a\" of undefined\n"
+ " at anonymous (:1)\n"
+ " at [Symbol.replace] (native)\n"
+ " at replace (native)\n"
+ " at f (:1)\n"
+ " at main (:1)\n"),
100 },
};
{ njs_str("var fs = require('fs'); fs.readFileSync()"),
njs_str("TypeError: \"path\" must be a string or Buffer\n"
- " at fs.readFileSync (native)\n"
+ " at readFileSync (native)\n"
" at main (:1)\n") },
{ njs_str("import fs from 'fs'; fs.readFileSync()"),
njs_str("TypeError: \"path\" must be a string or Buffer\n"
- " at fs.readFileSync (native)\n"
+ " at readFileSync (native)\n"
" at main (:1)\n") },
{ njs_str("var f = new Function('return 1;'); f();"),
{ njs_str("Array.prototype.push.call(preload.a, 'waka')"),
njs_str("TypeError: Cannot add property \"2\", object is not extensible\n"
- " at Array.prototype.push (native)\n"
- " at Function.prototype.call (native)\n"
+ " at push (native)\n"
+ " at call (native)\n"
" at main (:1)\n") },
};
" function(m) {return m.a.a})"),
njs_str("TypeError: cannot get property \"a\" of undefined\n"
" at anonymous (:1)\n"
- " at RegExp.prototype[Symbol.replace] (native)\n"
- " at String.prototype.replace (native)\n"
+ " at [Symbol.replace] (native)\n"
+ " at replace (native)\n"
" at main (:1)\n") },
{ njs_str("function f(o) {return Object.keys(o)};"
"f()"),
njs_str("TypeError: cannot convert undefined argument to object\n"
- " at Object.keys (native)\n"
+ " at keys (native)\n"
" at f (:1)\n"
" at main (:1)\n") },
{ njs_str("[].concat({}.a.a)"),
njs_str("TypeError: cannot get property \"a\" of undefined\n"
- " at Array.prototype.concat (native)\n"
+ " at concat (native)\n"
" at main (:1)\n") },
{ njs_str("''.repeat(-1)"),
njs_str("RangeError: invalid count value\n"
- " at String.prototype.repeat (native)\n"
+ " at repeat (native)\n"
" at main (:1)\n") },
{ njs_str("Math.log({}.a.a)"),
njs_str("TypeError: cannot get property \"a\" of undefined\n"
- " at Math.log (native)\n"
+ " at log (native)\n"
" at main (:1)\n") },
{ njs_str("var bound = Math.max.bind(null, {toString(){return {}}}); bound(1)"),
njs_str("TypeError: Cannot convert object to primitive value\n"
- " at Math.max (native)\n"
+ " at max (native)\n"
" at main (:1)\n") },
{ njs_str("var ab = new ArrayBuffer(1);"
"$262.detachArrayBuffer(ab);"
"ab.slice(0)"),
njs_str("TypeError: detached buffer\n"
- " at ArrayBuffer.prototype.slice (native)\n"
+ " at slice (native)\n"
" at main (:1)\n") },
{ njs_str("Object.prototype()"),
{ njs_str("$shared.method({}.a.a)"),
njs_str("TypeError: cannot get property \"a\" of undefined\n"
- " at $shared.method (native)\n"
+ " at method (native)\n"
" at main (:1)\n") },
{ njs_str("new Function(\n\n@)"),
{ njs_str("require('crypto').createHash('sha')"),
njs_str("TypeError: not supported algorithm: \"sha\"\n"
- " at crypto.createHash (native)\n"
+ " at createHash (native)\n"
" at main (:1)\n") },
{ njs_str("var h = require('crypto').createHash('sha1');"
"h.update([])"),
njs_str("TypeError: data is not a string or Buffer-like object\n"
- " at Hash.update (native)\n"
+ " at update (native)\n"
" at main (:1)\n") },
{ njs_str("require('crypto').createHmac('sha1', [])"),
njs_str("TypeError: key is not a string or Buffer-like object\n"
- " at crypto.createHmac (native)\n"
+ " at createHmac (native)\n"
" at main (:1)\n") },
{ njs_str("var h = require('crypto').createHmac('sha1', 'secret');"
"h.update([])"),
njs_str("TypeError: data is not a string or Buffer-like object\n"
- " at Hmac.update (native)\n"
+ " at update (native)\n"
" at main (:1)\n") },
{ njs_str("function f(o) {function f_in(o) {return o.a.a};"
" 'realpath',"
" 'realpathSync',"
"]"
- ".every(v=>{ try {fs[v]();} catch (e) { return e.stack.search(`fs.${v} `) >= 0}})"),
+ ".every(v=>{ try {fs[v]();} catch (e) { return e.stack.search(`at ${v} `) >= 0}})"),
njs_str("true") },
{ njs_str("parseInt({ toString: function() { return [1] } })"),
{ njs_str("Object.defineProperty(Function.__proto__, 'name', {get() { typeof 1;}});"
"(new Uint8Array()).every()"),
njs_str("TypeError: callback argument is not callable\n"
- " at TypedArray.prototype.every (native)\n"
+ " at every (native)\n"
" at main (:1)\n") },
{ njs_str("var e = new Error('oops'); e.stack = 123; e.stack"),
{ njs_str("Math\n.min(1,\na)"),
njs_str("ReferenceError: \"a\" is not defined\n"
- " at Math.min (native)\n"
+ " at min (native)\n"
" at main (:3)\n") },
};
# Backtraces for external objects
njs_test {
{"console.info(console.a.a)\r\n"
- "console.info(console.a.a)\r\nThrown:\r\nTypeError:*at console.info (native)"}
+ "console.info(console.a.a)\r\nThrown:\r\nTypeError:*at info (native)"}
}
# dumper