details: http://hg.nginx.org/njs/rev/7e4b13d45b30 branches: changeset: 504:7e4b13d45b30 user: Dmitry Volyntsev <xei...@nginx.com> date: Thu Apr 26 19:11:28 2018 +0300 description: Fixed handling of undefined arguments of functions.
This fixes #7 issue on GitHub. diffstat: njs/njs_array.c | 4 +- njs/njs_function.h | 3 + njs/njs_object.c | 282 ++++++++++++++++++++++++++-------------------- njs/njs_object.h | 4 +- njs/test/njs_unit_test.c | 9 +- 5 files changed, 174 insertions(+), 128 deletions(-) diffs (707 lines): diff -r 29eee021e03e -r 7e4b13d45b30 njs/njs_array.c --- a/njs/njs_array.c Thu Apr 26 19:11:28 2018 +0300 +++ b/njs/njs_array.c Thu Apr 26 19:11:28 2018 +0300 @@ -1628,7 +1628,7 @@ njs_array_prototype_find_apply(njs_vm_t /* GC: array elt, array */ - value = (nargs > 2) ? &args[2] : &njs_value_void; + value = njs_arg(args, nargs, 2); arguments[0] = *value; n = iter->index; @@ -1847,7 +1847,7 @@ njs_array_iterator_apply(njs_vm_t *vm, n /* GC: array elt, array */ - value = (nargs > 2) ? &args[2] : &njs_value_void; + value = njs_arg(args, nargs, 2); arguments[0] = *value; n = iter->index; diff -r 29eee021e03e -r 7e4b13d45b30 njs/njs_function.h --- a/njs/njs_function.h Thu Apr 26 19:11:28 2018 +0300 +++ b/njs/njs_function.h Thu Apr 26 19:11:28 2018 +0300 @@ -40,6 +40,9 @@ struct njs_function_lambda_s { }; +#define njs_arg(args, nargs, n) \ + ((n < nargs) ? &(args)[n] : &njs_value_void) + /* The frame size must be aligned to njs_value_t. */ #define NJS_NATIVE_FRAME_SIZE \ nxt_align_size(sizeof(njs_native_frame_t), sizeof(njs_value_t)) diff -r 29eee021e03e -r 7e4b13d45b30 njs/njs_object.c --- a/njs/njs_object.c Thu Apr 26 19:11:28 2018 +0300 +++ b/njs/njs_object.c Thu Apr 26 19:11:28 2018 +0300 @@ -28,7 +28,7 @@ static nxt_int_t njs_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data); static njs_ret_t njs_define_property(njs_vm_t *vm, njs_object_t *object, - njs_value_t *name, njs_object_t *descriptor); + const njs_value_t *name, const njs_object_t *descriptor); nxt_noinline njs_object_t * @@ -201,7 +201,8 @@ njs_object_prop_alloc(njs_vm_t *vm, cons nxt_noinline njs_object_prop_t * -njs_object_property(njs_vm_t *vm, njs_object_t *object, nxt_lvlhsh_query_t *lhq) +njs_object_property(njs_vm_t *vm, const njs_object_t *object, + nxt_lvlhsh_query_t *lhq) { nxt_int_t ret; @@ -232,13 +233,14 @@ njs_ret_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_uint_t type; - njs_value_t *value; - njs_object_t *object; + nxt_uint_t type; + njs_object_t *object; + const njs_value_t *value; type = NJS_OBJECT; + value = njs_arg(args, nargs, 1); - if (nargs == 1 || njs_is_null_or_void(&args[1])) { + if (njs_is_null_or_void(value)) { object = njs_object_alloc(vm); if (nxt_slow_path(object == NULL)) { @@ -246,7 +248,6 @@ njs_object_constructor(njs_vm_t *vm, njs } } else { - value = &args[1]; if (njs_is_object(value)) { object = value->data.u.object; @@ -283,34 +284,35 @@ static njs_ret_t njs_object_create(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_object_t *object; + njs_object_t *object; + const njs_value_t *value; - if (nargs > 1) { + value = njs_arg(args, nargs, 1); - if (njs_is_object(&args[1]) || njs_is_null(&args[1])) { + if (njs_is_object(value) || njs_is_null(value)) { - object = njs_object_alloc(vm); - if (nxt_slow_path(object == NULL)) { - return NXT_ERROR; - } + object = njs_object_alloc(vm); + if (nxt_slow_path(object == NULL)) { + return NXT_ERROR; + } - if (!njs_is_null(&args[1])) { - /* GC */ - object->__proto__ = args[1].data.u.object; + if (!njs_is_null(value)) { + /* GC */ + object->__proto__ = value->data.u.object; - } else { - object->__proto__ = NULL; - } + } else { + object->__proto__ = NULL; + } - vm->retval.data.u.object = object; - vm->retval.type = NJS_OBJECT; - vm->retval.data.truth = 1; + vm->retval.data.u.object = object; + vm->retval.type = NJS_OBJECT; + vm->retval.data.truth = 1; - return NXT_OK; - } + return NXT_OK; } - njs_type_error(vm, "too few arguments", NULL); + njs_type_error(vm, "prototype may only be an object or null: %s", + njs_type_string(value->type)); return NXT_ERROR; } @@ -320,16 +322,19 @@ static njs_ret_t njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_array_t *keys; + njs_array_t *keys; + const njs_value_t *value; - if (nargs < 2 || !njs_is_object(&args[1])) { + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { njs_type_error(vm, "cannot convert %s argument to object", - (nargs >= 2) ? njs_type_string(args[1].type) : "null"); + njs_type_string(value->type)); return NXT_ERROR; } - keys = njs_object_keys_array(vm, &args[1]); + keys = njs_object_keys_array(vm, value); if (keys == NULL) { njs_memory_error(vm); return NXT_ERROR; @@ -343,7 +348,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_ } njs_array_t* -njs_object_keys_array(njs_vm_t *vm, njs_value_t *object) +njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object) { size_t size; uint32_t i, n, keys_length, array_length; @@ -427,33 +432,38 @@ njs_object_define_property(njs_vm_t *vm, njs_index_t unused) { nxt_int_t ret; - const char *type; + const njs_value_t *value, *name, *descriptor; + + value = njs_arg(args, nargs, 1); - if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) { - if (nargs < 2 || !njs_is_object(&args[1])) { - type = (nargs > 1) ? njs_type_string(args[1].type) : "null"; - njs_type_error(vm, "cannot convert %s argument to object", type); - - } else { - njs_type_error(vm, "descriptor is not an object", NULL); - } - + if (!njs_is_object(value)) { + njs_type_error(vm, "cannot convert %s argument to object", + njs_type_string(value->type)); return NXT_ERROR; } - if (!args[1].data.u.object->extensible) { + if (!value->data.u.object->extensible) { njs_type_error(vm, "object is not extensible", NULL); return NXT_ERROR; } - ret = njs_define_property(vm, args[1].data.u.object, &args[2], - args[3].data.u.object); + descriptor = njs_arg(args, nargs, 3); + + if (!njs_is_object(descriptor)){ + njs_type_error(vm, "descriptor is not an object", NULL); + return NXT_ERROR; + } + + name = njs_arg(args, nargs, 2); + + ret = njs_define_property(vm, value->data.u.object, name, + descriptor->data.u.object); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } - vm->retval = args[1]; + vm->retval = *value; return NXT_OK; } @@ -464,33 +474,37 @@ njs_object_define_properties(njs_vm_t *v njs_index_t unused) { nxt_int_t ret; - const char *type; nxt_lvlhsh_t *hash; njs_object_t *object; nxt_lvlhsh_each_t lhe; njs_object_prop_t *prop; + const njs_value_t *value, *descriptor; - if (nargs < 3 || !njs_is_object(&args[1]) || !njs_is_object(&args[2])) { - if (nargs < 2 || !njs_is_object(&args[1])) { - type = (nargs > 1) ? njs_type_string(args[1].type) : "null"; - njs_type_error(vm, "cannot convert %s argument to object", type); + value = njs_arg(args, nargs, 1); - } else { - njs_type_error(vm, "descriptor is not an object", NULL); - } + if (!njs_is_object(value)) { + njs_type_error(vm, "cannot convert %s argument to object", + njs_type_string(value->type)); return NXT_ERROR; } - if (!args[1].data.u.object->extensible) { + if (!value->data.u.object->extensible) { njs_type_error(vm, "object is not extensible", NULL); return NXT_ERROR; } + descriptor = njs_arg(args, nargs, 2); + + if (!njs_is_object(descriptor)) { + njs_type_error(vm, "descriptor is not an object", NULL); + return NXT_ERROR; + } + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - object = args[1].data.u.object; - hash = &args[2].data.u.object->hash; + object = value->data.u.object; + hash = &descriptor->data.u.object->hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -509,15 +523,15 @@ njs_object_define_properties(njs_vm_t *v } } - vm->retval = args[1]; + vm->retval = *value; return NXT_OK; } static njs_ret_t -njs_define_property(njs_vm_t *vm, njs_object_t *object, njs_value_t *name, - njs_object_t *descriptor) +njs_define_property(njs_vm_t *vm, njs_object_t *object, const njs_value_t *name, + const njs_object_t *descriptor) { nxt_int_t ret; njs_object_prop_t *prop, *pr; @@ -606,29 +620,31 @@ njs_object_get_own_property_descriptor(n { uint32_t index; nxt_int_t ret; - const char *type; njs_array_t *array; njs_object_t *descriptor; njs_object_prop_t *pr, *prop, array_prop; - const njs_value_t *value; + const njs_value_t *value, *property, *setval; nxt_lvlhsh_query_t lhq; - if (nargs < 3 || !njs_is_object(&args[1])) { - type = (nargs > 1) ? njs_type_string(args[1].type) : "null"; - njs_type_error(vm, "cannot convert %s argument to object", type); + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { + njs_type_error(vm, "cannot convert %s argument to object", + njs_type_string(value->type)); return NXT_ERROR; } prop = NULL; + property = njs_arg(args, nargs, 2); - if (njs_is_array(&args[1])) { - array = args[1].data.u.array; - index = njs_string_to_index(&args[2]); + if (njs_is_array(value)) { + array = value->data.u.array; + index = njs_string_to_index(property); if (index < array->length && njs_is_valid(&array->start[index])) { prop = &array_prop; - array_prop.name = args[2]; + array_prop.name = *property; array_prop.value = array->start[index]; array_prop.configurable = 1; @@ -640,10 +656,10 @@ njs_object_get_own_property_descriptor(n lhq.proto = &njs_object_hash_proto; if (prop == NULL) { - njs_string_get(&args[2], &lhq.key); + njs_string_get(property, &lhq.key); lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - ret = nxt_lvlhsh_find(&args[1].data.u.object->hash, &lhq); + ret = nxt_lvlhsh_find(&value->data.u.object->hash, &lhq); if (ret != NXT_OK) { vm->retval = njs_string_void; @@ -679,9 +695,9 @@ njs_object_get_own_property_descriptor(n lhq.key = nxt_string_value("configurable"); lhq.key_hash = NJS_CONFIGURABLE_HASH; - value = (prop->configurable == 1) ? &njs_string_true : &njs_string_false; + setval = (prop->configurable == 1) ? &njs_string_true : &njs_string_false; - pr = njs_object_prop_alloc(vm, &njs_object_configurable_string, value, 1); + pr = njs_object_prop_alloc(vm, &njs_object_configurable_string, setval, 1); if (nxt_slow_path(pr == NULL)) { return NXT_ERROR; } @@ -696,9 +712,9 @@ njs_object_get_own_property_descriptor(n lhq.key = nxt_string_value("enumerable"); lhq.key_hash = NJS_ENUMERABLE_HASH; - value = (prop->enumerable == 1) ? &njs_string_true : &njs_string_false; + setval = (prop->enumerable == 1) ? &njs_string_true : &njs_string_false; - pr = njs_object_prop_alloc(vm, &njs_object_enumerable_string, value, 1); + pr = njs_object_prop_alloc(vm, &njs_object_enumerable_string, setval, 1); if (nxt_slow_path(pr == NULL)) { return NXT_ERROR; } @@ -713,9 +729,9 @@ njs_object_get_own_property_descriptor(n lhq.key = nxt_string_value("writable"); lhq.key_hash = NJS_WRITABABLE_HASH; - value = (prop->writable == 1) ? &njs_string_true : &njs_string_false; + setval = (prop->writable == 1) ? &njs_string_true : &njs_string_false; - pr = njs_object_prop_alloc(vm, &njs_object_writable_string, value, 1); + pr = njs_object_prop_alloc(vm, &njs_object_writable_string, setval, 1); if (nxt_slow_path(pr == NULL)) { return NXT_ERROR; } @@ -739,13 +755,19 @@ static njs_ret_t njs_object_get_prototype_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - if (nargs > 1 && njs_is_object(&args[1])) { - njs_object_prototype_get_proto(vm, &args[1], NULL, &vm->retval); + const njs_value_t *value; + + value = njs_arg(args, nargs, 1); + + if (njs_is_object(value)) { + njs_object_prototype_get_proto(vm, (njs_value_t *) value, NULL, + &vm->retval); return NXT_OK; } njs_type_error(vm, "cannot convert %s argument to object", - (nargs > 1) ? njs_type_string(args[1].type) : "null"); + njs_type_string(value->type)); + return NXT_ERROR; } @@ -758,13 +780,16 @@ njs_object_freeze(njs_vm_t *vm, njs_valu njs_object_t *object; njs_object_prop_t *prop; nxt_lvlhsh_each_t lhe; + const njs_value_t *value; - if (nargs < 2 || !njs_is_object(&args[1])) { + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { vm->retval = njs_value_void; return NXT_OK; } - object = args[1].data.u.object; + object = value->data.u.object; object->extensible = 0; nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); @@ -782,7 +807,7 @@ njs_object_freeze(njs_vm_t *vm, njs_valu prop->configurable = 0; } - vm->retval = args[1]; + vm->retval = *value; return NXT_OK; } @@ -796,16 +821,18 @@ njs_object_is_frozen(njs_vm_t *vm, njs_v njs_object_t *object; njs_object_prop_t *prop; nxt_lvlhsh_each_t lhe; - const njs_value_t *retval; + const njs_value_t *value, *retval; - if (nargs < 2 || !njs_is_object(&args[1])) { + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { vm->retval = njs_string_true; return NXT_OK; } retval = &njs_string_false; - object = args[1].data.u.object; + object = value->data.u.object; nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); hash = &object->hash; @@ -842,17 +869,18 @@ njs_object_seal(njs_vm_t *vm, njs_value_ { nxt_lvlhsh_t *hash; njs_object_t *object; - const njs_value_t *retval; + const njs_value_t *value; njs_object_prop_t *prop; nxt_lvlhsh_each_t lhe; - if (nargs < 2 || !njs_is_object(&args[1])) { - retval = (nargs < 2) ? &njs_value_void : &args[1]; - vm->retval = *retval; + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { + vm->retval = *value; return NXT_OK; } - object = args[1].data.u.object; + object = value->data.u.object; object->extensible = 0; nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); @@ -869,7 +897,7 @@ njs_object_seal(njs_vm_t *vm, njs_value_ prop->configurable = 0; } - vm->retval = args[1]; + vm->retval = *value; return NXT_OK; } @@ -883,16 +911,18 @@ njs_object_is_sealed(njs_vm_t *vm, njs_v njs_object_t *object; njs_object_prop_t *prop; nxt_lvlhsh_each_t lhe; - const njs_value_t *retval; + const njs_value_t *value, *retval; - if (nargs < 2 || !njs_is_object(&args[1])) { + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { vm->retval = njs_string_true; return NXT_OK; } retval = &njs_string_false; - object = args[1].data.u.object; + object = value->data.u.object; nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); hash = &object->hash; @@ -927,17 +957,18 @@ static njs_ret_t njs_object_prevent_extensions(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - const njs_value_t *retval; + const njs_value_t *value; - if (nargs < 2 || !njs_is_object(&args[1])) { - retval = (nargs < 2) ? &njs_value_void : &args[1]; - vm->retval = *retval; + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { + vm->retval = *value; return NXT_OK; } args[1].data.u.object->extensible = 0; - vm->retval = args[1]; + vm->retval = *value; return NXT_OK; } @@ -947,15 +978,17 @@ static njs_ret_t njs_object_is_extensible(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - const njs_value_t *retval; + const njs_value_t *value, *retval; - if (nargs < 2 || !njs_is_object(&args[1])) { + value = njs_arg(args, nargs, 1); + + if (!njs_is_object(value)) { vm->retval = njs_string_false; return NXT_OK; } - retval = args[1].data.u.object->extensible ? &njs_string_true - : &njs_string_false; + retval = value->data.u.object->extensible ? &njs_string_true + : &njs_string_false; vm->retval = *retval; @@ -1006,9 +1039,9 @@ njs_ret_t njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { - int32_t index; - njs_value_t *proto; - njs_function_t *function; + int32_t index; + njs_function_t *function; + const njs_value_t *proto; proto = NULL; function = value->data.u.function; @@ -1020,7 +1053,7 @@ njs_object_prototype_create(njs_vm_t *vm } if (proto == NULL) { - proto = (njs_value_t *) &njs_value_void; + proto = &njs_value_void; } *retval = *proto; @@ -1372,6 +1405,7 @@ njs_object_prototype_to_string(njs_vm_t { int32_t index; njs_object_t *object; + const njs_value_t *value; njs_object_prototype_t *prototype; static const njs_value_t *class_name[] = { @@ -1414,10 +1448,11 @@ njs_object_prototype_to_string(njs_vm_t &njs_object_object_value_string, }; - index = args[0].type; + value = &args[0]; + index = value->type; - if (njs_is_object(&args[0])) { - object = args[0].data.u.object; + if (njs_is_object(value)) { + object = value->data.u.object; do { prototype = (njs_object_prototype_t *) object; @@ -1452,16 +1487,19 @@ njs_object_prototype_has_own_property(nj uint32_t index; nxt_int_t ret; njs_array_t *array; - const njs_value_t *retval; + const njs_value_t *value, *prop, *retval; nxt_lvlhsh_query_t lhq; retval = &njs_string_false; + value = &args[0]; - if (nargs > 1 && njs_is_object(&args[0])) { + if (njs_is_object(value)) { - if (njs_is_array(&args[0])) { - array = args[0].data.u.array; - index = njs_string_to_index(&args[1]); + prop = njs_arg(args, nargs, 1); + + if (njs_is_array(value)) { + array = value->data.u.array; + index = njs_string_to_index(prop); if (index < array->length && njs_is_valid(&array->start[index])) { retval = &njs_string_true; @@ -1469,11 +1507,11 @@ njs_object_prototype_has_own_property(nj } } - njs_string_get(&args[1], &lhq.key); + njs_string_get(prop, &lhq.key); lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); lhq.proto = &njs_object_hash_proto; - ret = nxt_lvlhsh_find(&args[0].data.u.object->hash, &lhq); + ret = nxt_lvlhsh_find(&value->data.u.object->hash, &lhq); if (ret == NXT_OK) { retval = &njs_string_true; @@ -1493,13 +1531,15 @@ njs_object_prototype_is_prototype_of(njs nxt_uint_t nargs, njs_index_t unused) { njs_object_t *object, *proto; - const njs_value_t *retval; + const njs_value_t *value, *obj, *retval; retval = &njs_string_false; + value = &args[0]; + obj = njs_arg(args, nargs, 1); - if (nargs > 1 && njs_is_object(&args[0]) && njs_is_object(&args[1])) { - proto = args[0].data.u.object; - object = args[1].data.u.object; + if (njs_is_object(value) && njs_is_object(obj)) { + proto = value->data.u.object; + object = obj->data.u.object; do { object = object->__proto__; diff -r 29eee021e03e -r 7e4b13d45b30 njs/njs_object.h --- a/njs/njs_object.h Thu Apr 26 19:11:28 2018 +0300 +++ b/njs/njs_object.h Thu Apr 26 19:11:28 2018 +0300 @@ -41,8 +41,8 @@ njs_object_t *njs_object_alloc(njs_vm_t njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value); njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, nxt_uint_t type); -njs_array_t *njs_object_keys_array(njs_vm_t *vm, njs_value_t *object); -njs_object_prop_t *njs_object_property(njs_vm_t *vm, njs_object_t *obj, +njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object); +njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj, nxt_lvlhsh_query_t *lhq); nxt_int_t njs_object_hash_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, const njs_object_prop_t *prop, nxt_uint_t n); diff -r 29eee021e03e -r 7e4b13d45b30 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Apr 26 19:11:28 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Apr 26 19:11:28 2018 +0300 @@ -6366,7 +6366,10 @@ static njs_unit_test_t njs_test[] = nxt_string("false") }, { nxt_string("Object.create()"), - nxt_string("TypeError: too few arguments") }, + nxt_string("TypeError: prototype may only be an object or null: void") }, + + { nxt_string("Object.create(1)"), + nxt_string("TypeError: prototype may only be an object or null: number") }, { nxt_string("var o = {a:1, b:2, c:3};" "Object.keys(o)"), @@ -6382,7 +6385,7 @@ static njs_unit_test_t njs_test[] = nxt_string("1,3,one") }, { nxt_string("Object.keys()"), - nxt_string("TypeError: cannot convert null argument to object") }, + nxt_string("TypeError: cannot convert void argument to object") }, { nxt_string("Object.keys('a')"), nxt_string("TypeError: cannot convert string argument to object") }, @@ -6443,7 +6446,7 @@ static njs_unit_test_t njs_test[] = nxt_string("2") }, { nxt_string("var o = {}; Object.defineProperty()"), - nxt_string("TypeError: cannot convert null argument to object") }, + nxt_string("TypeError: cannot convert void argument to object") }, { nxt_string("var o = {}; Object.defineProperty(o)"), nxt_string("TypeError: descriptor is not an object") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel