From aa246eb2b406b8d537823c56550e129f2e0a9203 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Tue, 15 Nov 2016 17:43:05 +0300 Subject: [PATCH] Native methods and non-constructor functions must throw TypeError exception if they are called as constructor. --- njs/njs_builtin.c | 1 + njs/njs_vm.c | 22 +++++++++++++++++----- njs/njs_vm.h | 16 +++------------- njs/test/njs_unit_test.c | 6 ++++++ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c index e3dace3c..35a7f42d 100644 --- a/njs/njs_builtin.c +++ b/njs/njs_builtin.c @@ -237,6 +237,7 @@ njs_builtin_objects_create(njs_vm_t *vm) for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { constructors[i].object.shared = 0; constructors[i].native = 1; + constructors[i].ctor = 1; constructors[i].args_offset = 1; constructors[i].u.native = native_constructors[i].native; constructors[i].args_types[0] = native_constructors[i].args_types[0]; diff --git a/njs/njs_vm.c b/njs/njs_vm.c index cff396b7..ee86bf4d 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -2152,6 +2152,7 @@ njs_ret_t njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs) { njs_ret_t ret; + nxt_bool_t ctor; njs_value_t val, *this; njs_object_t *object; njs_function_t *function; @@ -2160,13 +2161,17 @@ njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs) if (nxt_fast_path(njs_is_function(value))) { func = (njs_vmcode_function_frame_t *) vm->current; + ctor = func->code.ctor; function = value->data.u.function; if (function->native) { + if (ctor && !function->ctor) { + goto fail; + } + ret = njs_function_native_frame(vm, function, &njs_value_void, - NULL, (uintptr_t) nargs, 0, - func->code.ctor); + NULL, (uintptr_t) nargs, 0, ctor); if (nxt_fast_path(ret == NXT_OK)) { return sizeof(njs_vmcode_function_frame_t); @@ -2175,7 +2180,7 @@ njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs) return ret; } - if (func->code.ctor) { + if (ctor) { object = njs_function_new_object(vm, value); if (nxt_slow_path(object == NULL)) { return NXT_ERROR; @@ -2191,7 +2196,7 @@ njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs) } ret = njs_function_frame(vm, function, this, NULL, (uintptr_t) nargs, - func->code.ctor); + ctor); if (nxt_fast_path(ret == NXT_OK)) { return sizeof(njs_vmcode_function_frame_t); @@ -2200,6 +2205,8 @@ njs_vmcode_function_frame(njs_vm_t *vm, njs_value_t *value, njs_value_t *nargs) return ret; } +fail: + vm->exception = &njs_exception_type_error; return NXT_ERROR; @@ -2329,8 +2336,13 @@ njs_vmcode_method_call(njs_vm_t *vm, njs_value_t *object, njs_value_t *value) return ret; } + if (method->code.ctor) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + ret = njs_function_native_frame(vm, function, object, NULL, method->nargs, - 0, method->code.ctor); + 0, 0); if (nxt_fast_path(ret == NXT_OK)) { njs_retain(object); diff --git a/njs/njs_vm.h b/njs/njs_vm.h index 06ed0cf3..af185ca6 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -230,20 +230,10 @@ struct njs_function_s { uint8_t args_types[NJS_ARGS_TYPES_MAX]; uint8_t args_offset; - - /* - * TODO Shared - * When function object is used as value: in assignments, - * as function argument, as property and as object to get properties. - */ - -#if (NXT_64BIT) - uint8_t native; - uint8_t continuation_size; -#else - uint8_t native; uint8_t continuation_size; -#endif + + uint8_t native:1; + uint8_t ctor:1; union { njs_function_lambda_t *lambda; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 311c7974..7950735c 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -4223,6 +4223,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("var F = function (){}; typeof F.prototype"), nxt_string("object") }, + { nxt_string("new decodeURI('%00')"), + nxt_string("TypeError")}, + + { nxt_string("new ''.toString"), + nxt_string("TypeError")}, + { nxt_string("function F() { return Number }" "var o = new (F())(5);" "typeof o +' '+ o"), -- 2.47.3