From adf554cbbcd79ef2788ceca50348c7329c74da9d Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Thu, 25 Apr 2019 19:50:20 +0300 Subject: [PATCH] Fixed Date() constructor with one argument. This closes #144 issue on Github. --- njs/njs_date.c | 62 ++++++++++++++++++++++++++-------------- njs/njs_number.c | 2 +- njs/njs_number.h | 1 + njs/njs_vm.c | 53 ++++++++++++++++++++++++++++------ njs/njs_vm.h | 1 + njs/test/njs_unit_test.c | 36 +++++++++++++++++++++++ 6 files changed, 124 insertions(+), 31 deletions(-) diff --git a/njs/njs_date.c b/njs/njs_date.c index 04e61ec1..d3ffc355 100644 --- a/njs/njs_date.c +++ b/njs/njs_date.c @@ -61,6 +61,17 @@ njs_gettime(void) } +static nxt_noinline double +njs_timeclip(double time) +{ + if (isinf(time) || isnan(time) || fabs(time) > 8.64e15) { + return NAN; + } + + return njs_number_to_int64(time); +} + + njs_ret_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) @@ -76,8 +87,22 @@ njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, if (nargs == 1) { time = njs_gettime(); - } else if (nargs == 2 && njs_is_string(&args[1])) { - time = njs_date_string_parse(&args[1]); + } else if (nargs == 2) { + if (njs_is_object(&args[1])) { + if (!njs_is_date(&args[1])) { + njs_vm_trap_value(vm, &args[1]); + + return njs_trap(vm, NJS_TRAP_PRIMITIVE_ARG); + } + + time = args[1].data.u.date->time; + + } else if (njs_is_string(&args[1])) { + time = njs_date_string_parse(&args[1]); + + } else { + time = args[1].data.u.number; + } } else { nxt_memzero(values, 8 * sizeof(int64_t)); @@ -103,25 +128,20 @@ njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, values[i] = num; } - if (nargs > 2) { - /* Year. */ - if (values[1] > 99) { - values[1] -= 1900; - } - - tm.tm_year = values[1]; - tm.tm_mon = values[2]; - tm.tm_mday = values[3]; - tm.tm_hour = values[4]; - tm.tm_min = values[5]; - tm.tm_sec = values[6]; - tm.tm_isdst = -1; + /* Year. */ + if (values[1] > 99) { + values[1] -= 1900; + } - time = (int64_t) mktime(&tm) * 1000 + values[7]; + tm.tm_year = values[1]; + tm.tm_mon = values[2]; + tm.tm_mday = values[3]; + tm.tm_hour = values[4]; + tm.tm_min = values[5]; + tm.tm_sec = values[6]; + tm.tm_isdst = -1; - } else { - time = values[1]; - } + time = (int64_t) mktime(&tm) * 1000 + values[7]; } done: @@ -139,7 +159,7 @@ njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, date->object.extensible = 1; date->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_DATE].object; - date->time = time; + date->time = njs_timeclip(time); vm->retval.data.u.date = date; vm->retval.type = NJS_DATE; @@ -1048,7 +1068,7 @@ njs_date_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *date) return njs_string_new(vm, retval, buf, p - buf, p - buf); } - vm->retval = njs_string_invalid_date; + *retval = njs_string_invalid_date; return NXT_OK; } diff --git a/njs/njs_number.c b/njs/njs_number.c index 9bca4c8f..e129a3cd 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -804,7 +804,7 @@ njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } -nxt_inline int64_t +int64_t njs_number_to_int64(double num) { #if (NXT_NAN_TO_UINT_CONVERSION != 0) diff --git a/njs/njs_number.h b/njs/njs_number.h index 5e67651b..47c6c618 100644 --- a/njs/njs_number.h +++ b/njs/njs_number.h @@ -35,6 +35,7 @@ njs_ret_t njs_number_parse_int(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +int64_t njs_number_to_int64(double num); nxt_noinline int32_t njs_number_to_integer(double num); nxt_noinline int32_t njs_number_to_int32(double num); nxt_noinline uint32_t njs_number_to_uint32(double num); diff --git a/njs/njs_vm.c b/njs/njs_vm.c index 5d2728c5..c28cb88d 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -50,6 +50,8 @@ static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2); static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *inlvd2); +static njs_ret_t njs_vmcode_primitive_argument(njs_vm_t *vm, + njs_value_t *invld1, njs_value_t *inlvd2); static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint); static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, @@ -199,6 +201,7 @@ start: case NJS_TRAP_NUMBER_ARG: case NJS_TRAP_STRING_ARG: + case NJS_TRAP_PRIMITIVE_ARG: njs_vm_trap_argument(vm, trap); @@ -2608,16 +2611,24 @@ static const njs_vmcode_1addr_t njs_trap_string_argument = { }; +static const njs_vmcode_1addr_t njs_trap_primitive_argument = { + .code = { .operation = njs_vmcode_primitive_argument, + .operands = NJS_VMCODE_NO_OPERAND, + .retval = NJS_VMCODE_NO_RETVAL } +}; + + static const njs_vm_trap_t njs_vm_traps[] = { - /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, - /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, - /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, - /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, - /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], - .reference = 1 }, - /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, - /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, - /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, + /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] }, + /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] }, + /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] }, + /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] }, + /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1], + .reference = 1 }, + /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] }, + /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument }, + /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument }, + /* NJS_TRAP_PRIMITIVE_ARG */ { .code = &njs_trap_primitive_argument }, }; @@ -2830,6 +2841,30 @@ njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1, } +static njs_ret_t +njs_vmcode_primitive_argument(njs_vm_t *vm, njs_value_t *invld1, + njs_value_t *inlvd2) +{ + njs_ret_t ret; + njs_value_t *value; + + value = &vm->top_frame->trap_values[0]; + + ret = njs_primitive_value(vm, value, 0); + + if (nxt_fast_path(ret > 0)) { + *vm->top_frame->trap_values[1].data.u.value = *value; + + vm->current = vm->top_frame->trap_restart; + vm->top_frame->trap_restart = NULL; + + return 0; + } + + return ret; +} + + static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2) { diff --git a/njs/njs_vm.h b/njs/njs_vm.h index 57c01333..342d7beb 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -47,6 +47,7 @@ typedef enum { NJS_TRAP_PROPERTY, NJS_TRAP_NUMBER_ARG, NJS_TRAP_STRING_ARG, + NJS_TRAP_PRIMITIVE_ARG, } njs_trap_t; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 6cfe0018..27edbbb3 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -9563,12 +9563,48 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.isExtensible(Object.freeze([]))"), nxt_string("false") }, + { nxt_string("new Date(undefined)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(Infinity)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(NaN)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(8.65e15)"), + nxt_string("Invalid Date") }, + + { nxt_string("new Date(0e0.o0)"), + nxt_string("Invalid Date") }, + + { nxt_string("(new Date(8.639e15)).getTime()"), + nxt_string("8639000000000000") }, + + { nxt_string("new Date(8.641e15)"), + nxt_string("Invalid Date") }, + + { nxt_string("(new Date(null)).getTime()"), + nxt_string("0") }, + + { nxt_string("(new Date(86400)).getTime()"), + nxt_string("86400") }, + { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") }, { nxt_string("var d = new Date(1); d = d + ''; d.slice(0, 33)"), nxt_string("Thu Jan 01 1970 00:00:00 GMT+0000") }, + { nxt_string("var d = new Date({valueOf:()=>86400000}); d = d + ''; d.slice(0, 33)"), + nxt_string("Fri Jan 02 1970 00:00:00 GMT+0000") }, + + { nxt_string("(new Date({toString:()=>'2011'})).getTime()"), + nxt_string("1293840000000") }, + + { nxt_string("(new Date({valueOf: ()=>86400, toString:()=>'2011'})).getTime()"), + nxt_string("86400") }, + { nxt_string("var d = new Date(1308895200000); d.getTime()"), nxt_string("1308895200000") }, -- 2.47.3