From alexander.borisov at nginx.com Mon Jun 1 15:11:03 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 01 Jun 2020 15:11:03 +0000 Subject: [njs] Fixed potential NULL-pointer dereference added in 86f55a7dc4a4. Message-ID: details: https://hg.nginx.org/njs/rev/c9f07d5eef98 branches: changeset: 1409:c9f07d5eef98 user: Alexander Borisov date: Mon Jun 01 18:09:27 2020 +0300 description: Fixed potential NULL-pointer dereference added in 86f55a7dc4a4. Found by Coverity (CID 1463867). diffstat: src/njs_parser.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r d255e73aed3b -r c9f07d5eef98 src/njs_parser.c --- a/src/njs_parser.c Fri May 29 19:29:59 2020 +0000 +++ b/src/njs_parser.c Mon Jun 01 18:09:27 2020 +0300 @@ -5383,7 +5383,7 @@ njs_parser_for_in_statement(njs_parser_t } forin = njs_parser_node_new(parser, NJS_TOKEN_FOR_IN); - if (node == NULL) { + if (forin == NULL) { return NJS_ERROR; } From alexander.borisov at nginx.com Mon Jun 1 15:11:05 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 01 Jun 2020 15:11:05 +0000 Subject: [njs] Removed unnecessary NULL checks introduced in 86f55a7dc4a4. Message-ID: details: https://hg.nginx.org/njs/rev/c37e682982b1 branches: changeset: 1410:c37e682982b1 user: Alexander Borisov date: Mon Jun 01 18:09:28 2020 +0300 description: Removed unnecessary NULL checks introduced in 86f55a7dc4a4. Found by Clang static analyzer. diffstat: src/njs_parser.c | 20 +++++++------------- src/test/njs_unit_test.c | 3 +-- 2 files changed, 8 insertions(+), 15 deletions(-) diffs (50 lines): diff -r c9f07d5eef98 -r c37e682982b1 src/njs_parser.c --- a/src/njs_parser.c Mon Jun 01 18:09:27 2020 +0300 +++ b/src/njs_parser.c Mon Jun 01 18:09:28 2020 +0300 @@ -1929,7 +1929,7 @@ njs_parser_property_definition_after(njs proto_init = 0; - if (property != NULL && property->index != NJS_TOKEN_OPEN_BRACKET + if (property->index != NJS_TOKEN_OPEN_BRACKET && njs_is_string(&property->u.value)) { njs_string_get(&property->u.value, &name); @@ -3891,18 +3891,12 @@ njs_parser_coalesce_expression(njs_parse return njs_parser_stack_pop(parser); } - if (node != NULL) { - type = node->token_type; - - if (parser->lexer->prev_type != NJS_TOKEN_CLOSE_PARENTHESIS - && (type == NJS_TOKEN_LOGICAL_OR || type == NJS_TOKEN_LOGICAL_AND)) - { - njs_parser_syntax_error(parser, "Either \"??\" or \"%s\" " - "expression must be parenthesized", - (type == NJS_TOKEN_LOGICAL_OR) ? "||" - : "&&"); - return NJS_DONE; - } + type = node->token_type; + + if (parser->lexer->prev_type != NJS_TOKEN_CLOSE_PARENTHESIS + && (type == NJS_TOKEN_LOGICAL_OR || type == NJS_TOKEN_LOGICAL_AND)) + { + return njs_parser_failed(parser); } njs_lexer_consume_token(parser->lexer, 1); diff -r c9f07d5eef98 -r c37e682982b1 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Jun 01 18:09:27 2020 +0300 +++ b/src/test/njs_unit_test.c Mon Jun 01 18:09:28 2020 +0300 @@ -1344,8 +1344,7 @@ static njs_unit_test_t njs_test[] = njs_str("false") }, { njs_str("1 && 1 ?? true"), - njs_str("SyntaxError: Either \"??\" or \"&&\" expression " - "must be parenthesized in 1") }, + njs_str("SyntaxError: Unexpected token \"??\" in 1") }, { njs_str("null ?? 0 || 1"), njs_str("SyntaxError: Unexpected token \"||\" in 1") }, From alexander.borisov at nginx.com Mon Jun 1 15:11:06 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 01 Jun 2020 15:11:06 +0000 Subject: [njs] Fixed grammar introduced in 86f55a7dc4a4. Message-ID: details: https://hg.nginx.org/njs/rev/b4a6f26b7e32 branches: changeset: 1411:b4a6f26b7e32 user: Alexander Borisov date: Mon Jun 01 18:09:29 2020 +0300 description: Fixed grammar introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (16 lines): diff -r c37e682982b1 -r b4a6f26b7e32 src/njs_parser.c --- a/src/njs_parser.c Mon Jun 01 18:09:28 2020 +0300 +++ b/src/njs_parser.c Mon Jun 01 18:09:29 2020 +0300 @@ -467,10 +467,10 @@ njs_inline njs_int_t njs_parser_not_supported(njs_parser_t *parser, njs_lexer_token_t *token) { if (token->type != NJS_TOKEN_END) { - njs_parser_syntax_error(parser, "Token \"%V\" not support " + njs_parser_syntax_error(parser, "Token \"%V\" not supported " "in this version", &token->text); } else { - njs_parser_syntax_error(parser, "Not support in this version"); + njs_parser_syntax_error(parser, "Not supported in this version"); } return NJS_DONE; From alexander.borisov at nginx.com Mon Jun 1 15:11:08 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 01 Jun 2020 15:11:08 +0000 Subject: [njs] Silenced cast to smaller integer type warning. Message-ID: details: https://hg.nginx.org/njs/rev/ff39edb94acf branches: changeset: 1412:ff39edb94acf user: Alexander Borisov date: Mon Jun 01 18:09:29 2020 +0300 description: Silenced cast to smaller integer type warning. This fixes compilation with clang 11. diffstat: src/njs_parser.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff -r b4a6f26b7e32 -r ff39edb94acf src/njs_parser.c --- a/src/njs_parser.c Mon Jun 01 18:09:29 2020 +0300 +++ b/src/njs_parser.c Mon Jun 01 18:09:29 2020 +0300 @@ -6804,7 +6804,7 @@ njs_parser_get_set(njs_parser_t *parser, njs_parser_node_t *property, *expression, *temp; temp = parser->target; - accessor = (njs_token_type_t) temp->right; + accessor = (njs_token_type_t) (uintptr_t) temp->right; name = token; @@ -6906,7 +6906,7 @@ njs_parser_get_set_after(njs_parser_t *p temp = parser->target; - accessor = (njs_token_type_t) temp->right; + accessor = (njs_token_type_t) (uintptr_t) temp->right; temp->right = parser->node; parser->node = expression; From daareiza at gmail.com Mon Jun 1 17:44:15 2020 From: daareiza at gmail.com (Daniel Areiza) Date: Mon, 1 Jun 2020 12:44:15 -0500 Subject: [PATCH] Stream Upstream: ssl_early_data config option support Message-ID: # HG changeset patch # User Daniel Areiza # Date 1591030632 18000 # Mon Jun 01 11:57:12 2020 -0500 # Node ID 5b16afc16eb9ae778d6a26563a9f1a5ae3163704 # Parent 8cadaf7e7231865f2f81c03cb785c045dda6bf8b Stream Upstream: ssl_early_data config option support SSL early data config option support for streams diff -r 8cadaf7e7231 -r 5b16afc16eb9 src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c Tue May 26 19:17:11 2020 +0300 +++ b/src/stream/ngx_stream_ssl_module.c Mon Jun 01 11:57:12 2020 -0500 @@ -196,6 +196,13 @@ offsetof(ngx_stream_ssl_conf_t, crl), NULL }, + { ngx_string("ssl_early_data"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, early_data), + NULL }, + ngx_null_command }; @@ -286,6 +293,9 @@ { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_early_data"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_early_data, NGX_STREAM_VAR_CHANGEABLE, 0 }, + ngx_stream_null_variable }; @@ -602,6 +612,7 @@ scf->session_timeout = NGX_CONF_UNSET; scf->session_tickets = NGX_CONF_UNSET; scf->session_ticket_keys = NGX_CONF_UNSET_PTR; + scf->early_data = NGX_CONF_UNSET; return scf; } @@ -624,6 +635,8 @@ ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); + ngx_conf_merge_value(conf->early_data, prev->early_data, 0); + ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); @@ -811,6 +824,10 @@ return NGX_CONF_ERROR; } + if (ngx_ssl_early_data(cf, &conf->ssl, conf->early_data) != NGX_OK) { + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; } diff -r 8cadaf7e7231 -r 5b16afc16eb9 src/stream/ngx_stream_ssl_module.h --- a/src/stream/ngx_stream_ssl_module.h Tue May 26 19:17:11 2020 +0300 +++ b/src/stream/ngx_stream_ssl_module.h Mon Jun 01 11:57:12 2020 -0500 @@ -54,6 +54,8 @@ u_char *file; ngx_uint_t line; + + ngx_flag_t early_data; } ngx_stream_ssl_conf_t; From ru at nginx.com Mon Jun 1 19:33:04 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 01 Jun 2020 19:33:04 +0000 Subject: [nginx] Fixed removing of listening UNIX sockets when "changing binary". Message-ID: details: https://hg.nginx.org/nginx/rev/9c038f5e0464 branches: changeset: 7662:9c038f5e0464 user: Ruslan Ermilov date: Mon Jun 01 20:19:27 2020 +0300 description: Fixed removing of listening UNIX sockets when "changing binary". When changing binary, sending a SIGTERM to the new binary's master process should not remove inherited UNIX sockets unless the old binary's master process has exited. diffstat: src/core/nginx.c | 1 + src/core/ngx_connection.c | 3 ++- src/core/ngx_cycle.c | 1 + 3 files changed, 4 insertions(+), 1 deletions(-) diffs (35 lines): diff -r 8cadaf7e7231 -r 9c038f5e0464 src/core/nginx.c --- a/src/core/nginx.c Tue May 26 19:17:11 2020 +0300 +++ b/src/core/nginx.c Mon Jun 01 20:19:27 2020 +0300 @@ -492,6 +492,7 @@ ngx_add_inherited_sockets(ngx_cycle_t *c ngx_memzero(ls, sizeof(ngx_listening_t)); ls->fd = (ngx_socket_t) s; + ls->inherited = 1; } } diff -r 8cadaf7e7231 -r 9c038f5e0464 src/core/ngx_connection.c --- a/src/core/ngx_connection.c Tue May 26 19:17:11 2020 +0300 +++ b/src/core/ngx_connection.c Mon Jun 01 20:19:27 2020 +0300 @@ -1070,7 +1070,8 @@ ngx_close_listening_sockets(ngx_cycle_t if (ls[i].sockaddr->sa_family == AF_UNIX && ngx_process <= NGX_PROCESS_MASTER - && ngx_new_binary == 0) + && ngx_new_binary == 0 + && (!ls[i].inherited || ngx_getppid() != ngx_parent)) { u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; diff -r 8cadaf7e7231 -r 9c038f5e0464 src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c Tue May 26 19:17:11 2020 +0300 +++ b/src/core/ngx_cycle.c Mon Jun 01 20:19:27 2020 +0300 @@ -520,6 +520,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) == NGX_OK) { nls[n].fd = ls[i].fd; + nls[n].inherited = ls[i].inherited; nls[n].previous = &ls[i]; ls[i].remain = 1; From ru at nginx.com Mon Jun 1 19:33:07 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 01 Jun 2020 19:33:07 +0000 Subject: [nginx] Fixed SIGQUIT not removing listening UNIX sockets (closes #753). Message-ID: details: https://hg.nginx.org/nginx/rev/7cbf6389194b branches: changeset: 7663:7cbf6389194b user: Ruslan Ermilov date: Mon Jun 01 22:31:23 2020 +0300 description: Fixed SIGQUIT not removing listening UNIX sockets (closes #753). Listening UNIX sockets were not removed on graceful shutdown, preventing the next runs. The fix is to replace the custom socket closing code in ngx_master_process_cycle() by the ngx_close_listening_sockets() call. diffstat: src/os/unix/ngx_process_cycle.c | 14 ++------------ 1 files changed, 2 insertions(+), 12 deletions(-) diffs (35 lines): diff -r 9c038f5e0464 -r 7cbf6389194b src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c Mon Jun 01 20:19:27 2020 +0300 +++ b/src/os/unix/ngx_process_cycle.c Mon Jun 01 22:31:23 2020 +0300 @@ -77,12 +77,11 @@ ngx_master_process_cycle(ngx_cycle_t *cy u_char *p; size_t size; ngx_int_t i; - ngx_uint_t n, sigio; + ngx_uint_t sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; - ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); @@ -204,16 +203,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); - - ls = cycle->listening.elts; - for (n = 0; n < cycle->listening.nelts; n++) { - if (ngx_close_socket(ls[n].fd) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, - ngx_close_socket_n " %V failed", - &ls[n].addr_text); - } - } - cycle->listening.nelts = 0; + ngx_close_listening_sockets(cycle); continue; } From ru at nginx.com Mon Jun 1 19:46:06 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 1 Jun 2020 22:46:06 +0300 Subject: [PATCH] Ensured SIGQUIT deletes listening UNIX socket files. In-Reply-To: <6d8edc45-6133-de52-8220-05c962a4a48c@fastmail.com> References: <4b6bc48b-6c7a-7c76-51ae-1038421ed36c@fastmail.com> <20200227152429.GI12894@mdounin.ru> <2c06ad76-c309-d387-2c40-f6e60aacf4f8@fastmail.com> <20200303142811.GO12894@mdounin.ru> <22c4b64a-eb4e-a8a8-7428-34ab3225fcf5@fastmail.com> <20200426011240.GL20357@mdounin.ru> <6d8edc45-6133-de52-8220-05c962a4a48c@fastmail.com> Message-ID: <20200601194606.GA69408@lo0.su> Hi there, On Mon, Apr 27, 2020 at 04:26:31PM -0700, Thibault Charbonnier wrote: > On 4/25/20 6:12 PM, Maxim Dounin wrote: > > A better approach might be to check parent's pid instead, much > > like we do when handling the changebin signal on unix (see > > src/os/unix/ngx_process.c). > > Great! Thanks for the suggestion. Below is a revised approach for the > patch (also attached to this email) which passes all of the test cases > listed in my previous test file at the start of this thread: > > # HG changeset patch > # User Thibault Charbonnier > # Date 1582764433 28800 > # Wed Feb 26 16:47:13 2020 -0800 > # Node ID 8d781bac6c4feebb2d1ea3f4e6df76d71f74e43b > # Parent 4f18393a1d51bce6103ea2f1b2587900f349ba3d > Ensured SIGQUIT deletes listening UNIX socket files. > > Prior to this patch, the SIGQUIT signal handling (graceful shutdown) did not > remove UNIX socket files since ngx_master_process_cycle reimplemented listening > socket closings in lieu of using ngx_close_listening_sockets. > > Since ngx_master_process_exit will call the aforementioned > ngx_close_listening_sockets, we can remove the custom implementation and now > expect listening sockets to be closed properly by ngx_close_listening_sockets > instead. > > This fixes the trac issue #753 (https://trac.nginx.org/nginx/ticket/753). > > diff -r 4f18393a1d51 -r 8d781bac6c4f src/core/ngx_connection.c > --- a/src/core/ngx_connection.c Thu Feb 20 16:51:07 2020 +0300 > +++ b/src/core/ngx_connection.c Wed Feb 26 16:47:13 2020 -0800 > @@ -1070,7 +1070,8 @@ > > if (ls[i].sockaddr->sa_family == AF_UNIX > && ngx_process <= NGX_PROCESS_MASTER > - && ngx_new_binary == 0) > + && ngx_new_binary == 0 > + && ngx_getppid() != ngx_parent) > { > u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; > > diff -r 4f18393a1d51 -r 8d781bac6c4f src/os/unix/ngx_process_cycle.c > --- a/src/os/unix/ngx_process_cycle.c Thu Feb 20 16:51:07 2020 +0300 > +++ b/src/os/unix/ngx_process_cycle.c Wed Feb 26 16:47:13 2020 -0800 > @@ -77,12 +77,11 @@ > u_char *p; > size_t size; > ngx_int_t i; > - ngx_uint_t n, sigio; > + ngx_uint_t sigio; > sigset_t set; > struct itimerval itv; > ngx_uint_t live; > ngx_msec_t delay; > - ngx_listening_t *ls; > ngx_core_conf_t *ccf; > > sigemptyset(&set); > @@ -205,16 +204,6 @@ > ngx_signal_worker_processes(cycle, > ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); > > - ls = cycle->listening.elts; > - for (n = 0; n < cycle->listening.nelts; n++) { > - if (ngx_close_socket(ls[n].fd) == -1) { > - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, > - ngx_close_socket_n " %V failed", > - &ls[n].addr_text); > - } > - } > - cycle->listening.nelts = 0; > - > continue; > } > Thanks for your patch. Unfortunately, it would break removing of UNIX-domain socket files when nginx is run with "daemon off". It'd also add a regression that the master process will not remove the UNIX-domain socket files until after all worker processes have exited (this has been fixed in 0.1.40). The committed fixes: http://hg.nginx.org/nginx/rev/9c038f5e0464 http://hg.nginx.org/nginx/rev/7cbf6389194b From h312841925 at gmail.com Tue Jun 2 10:16:35 2020 From: h312841925 at gmail.com (Jim T) Date: Tue, 2 Jun 2020 18:16:35 +0800 Subject: Core: close pid file while writing it failed Message-ID: Hello, Maxim Dounin. How about below patch, could you help me review it? And I found the problem still exists in release-1.19.0, or do I miss anything? --- Hello! As far as I understand it, `ngx_create_pidfile` is a function that works independently. There is no action to close the pid file externally, so we need to close the pid file when the writing it failed. There are also reports here https://github.com/nginx/nginx/pull/52. # HG changeset patch # User Jinhua Tan <312841925 at qq.com> # Date 1590068494 -28800 # Thu May 21 21:41:34 2020 +0800 # Node ID 6084ea4d9a4d2ae32f3fc4e2e3b9032ab0b71e30 # Parent 3242f98298975e556a7e87130611ce84799fe935 Core: close pid file while writing it failed. diff -r 3242f9829897 -r 6084ea4d9a4d src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c Wed May 20 12:24:05 2020 +0800 +++ b/src/core/ngx_cycle.c Thu May 21 21:41:34 2020 +0800 @@ -1036,6 +1036,12 @@ len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file.name.data); + } + return NGX_ERROR; } } Thank you! -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.borisov at nginx.com Tue Jun 2 14:54:19 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 02 Jun 2020 14:54:19 +0000 Subject: [njs] Fixed checking return value in primary expression. Message-ID: details: https://hg.nginx.org/njs/rev/8923d0751c28 branches: changeset: 1413:8923d0751c28 user: Alexander Borisov date: Tue Jun 02 17:53:27 2020 +0300 description: Fixed checking return value in primary expression. The issue was introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 10 +++++++--- src/test/njs_unit_test.c | 9 ++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diffs (60 lines): diff -r ff39edb94acf -r 8923d0751c28 src/njs_parser.c --- a/src/njs_parser.c Mon Jun 01 18:09:29 2020 +0300 +++ b/src/njs_parser.c Tue Jun 02 17:53:27 2020 +0300 @@ -994,7 +994,7 @@ njs_parser_primary_expression_test(njs_p ret = njs_parser_escape_string_create(parser, token, &node->u.value); if (ret != NJS_TOKEN_STRING) { - return NJS_DONE; + return NJS_ERROR; } parser->node = node; @@ -1005,7 +1005,7 @@ njs_parser_primary_expression_test(njs_p njs_parser_syntax_error(parser, "Unterminated string \"%V\"", &token->text); - return NJS_DONE; + return NJS_ERROR; /* ArrayLiteral */ case NJS_TOKEN_OPEN_BRACKET: @@ -1086,7 +1086,7 @@ njs_parser_primary_expression_test(njs_p ret = njs_parser_regexp_literal(parser, token, current); if (ret != NJS_OK) { - return NJS_DONE; + return NJS_ERROR; } goto done; @@ -2210,6 +2210,10 @@ njs_parser_member_expression(njs_parser_ return NJS_OK; } + if (njs_is_error(&parser->vm->retval)) { + return NJS_DONE; + } + return ret; } diff -r ff39edb94acf -r 8923d0751c28 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Jun 01 18:09:29 2020 +0300 +++ b/src/test/njs_unit_test.c Tue Jun 02 17:53:27 2020 +0300 @@ -16652,7 +16652,14 @@ static njs_unit_test_t njs_test[] = "function foo() {}"), njs_str("undefined") }, - + { njs_str("new\""), + njs_str("SyntaxError: Unterminated string \"\"\" in 1") }, + + { njs_str("new\"\\UFFFF"), + njs_str("SyntaxError: Unterminated string \"\"\\UFFFF\" in 1") }, + + { njs_str("new/la"), + njs_str("SyntaxError: Unterminated RegExp \"/la\" in 1") }, }; From alexander.borisov at nginx.com Tue Jun 2 14:54:21 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 02 Jun 2020 14:54:21 +0000 Subject: [njs] Fixed parsing of invalid binary expressions. Message-ID: details: https://hg.nginx.org/njs/rev/ea1754b79e7a branches: changeset: 1414:ea1754b79e7a user: Alexander Borisov date: Tue Jun 02 17:53:28 2020 +0300 description: Fixed parsing of invalid binary expressions. The issue was introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- src/test/njs_unit_test.c | 3 +++ 2 files changed, 43 insertions(+), 8 deletions(-) diffs (176 lines): diff -r 8923d0751c28 -r ea1754b79e7a src/njs_parser.c --- a/src/njs_parser.c Tue Jun 02 17:53:27 2020 +0300 +++ b/src/njs_parser.c Tue Jun 02 17:53:28 2020 +0300 @@ -3086,6 +3086,10 @@ njs_parser_expression_node(njs_parser_t { njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3107,7 +3111,7 @@ njs_parser_expression_node(njs_parser_t node->left = parser->node; node->left->dest = node; - return njs_parser_after(parser, current, node, 1, after); + return njs_parser_after(parser, current, node, 0, after); } @@ -3398,6 +3402,10 @@ njs_parser_exponentiation_expression_mat { njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3423,7 +3431,7 @@ njs_parser_exponentiation_expression_mat njs_parser_next(parser, njs_parser_exponentiation_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_exponentiation_expression_match); } @@ -3449,6 +3457,10 @@ njs_parser_multiplicative_expression_mat njs_parser_node_t *node; njs_vmcode_operation_t operation; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3485,7 +3497,7 @@ njs_parser_multiplicative_expression_mat njs_parser_next(parser, njs_parser_exponentiation_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_multiplicative_expression_match); } @@ -3511,6 +3523,10 @@ njs_parser_additive_expression_match(njs njs_parser_node_t *node; njs_vmcode_operation_t operation; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3543,7 +3559,7 @@ njs_parser_additive_expression_match(njs njs_parser_next(parser, njs_parser_multiplicative_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_additive_expression_match); } @@ -3569,6 +3585,10 @@ njs_parser_shift_expression_match(njs_pa njs_parser_node_t *node; njs_vmcode_operation_t operation; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3605,7 +3625,7 @@ njs_parser_shift_expression_match(njs_pa njs_parser_next(parser, njs_parser_additive_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_shift_expression_match); } @@ -3631,6 +3651,10 @@ njs_parser_relational_expression_match(n njs_parser_node_t *node; njs_vmcode_operation_t operation; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3679,7 +3703,7 @@ njs_parser_relational_expression_match(n njs_parser_next(parser, njs_parser_shift_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_relational_expression_match); } @@ -3705,6 +3729,10 @@ njs_parser_equality_expression_match(njs njs_parser_node_t *node; njs_vmcode_operation_t operation; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3745,7 +3773,7 @@ njs_parser_equality_expression_match(njs njs_parser_next(parser, njs_parser_relational_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_equality_expression_match); } @@ -3883,6 +3911,10 @@ njs_parser_coalesce_expression(njs_parse njs_token_type_t type; njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + node = parser->node; if (parser->target != NULL) { @@ -3916,7 +3948,7 @@ njs_parser_coalesce_expression(njs_parse njs_parser_next(parser, njs_parser_bitwise_OR_expression); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_coalesce_expression); } diff -r 8923d0751c28 -r ea1754b79e7a src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 17:53:27 2020 +0300 +++ b/src/test/njs_unit_test.c Tue Jun 02 17:53:28 2020 +0300 @@ -16660,6 +16660,9 @@ static njs_unit_test_t njs_test[] = { njs_str("new/la"), njs_str("SyntaxError: Unterminated RegExp \"/la\" in 1") }, + + { njs_str("{name; {/ / /}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, }; From alexander.borisov at nginx.com Tue Jun 2 14:54:23 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 02 Jun 2020 14:54:23 +0000 Subject: [njs] Added necessary checks for obligatory grammar symbols. Message-ID: details: https://hg.nginx.org/njs/rev/4117ec04714b branches: changeset: 1415:4117ec04714b user: Alexander Borisov date: Tue Jun 02 17:53:29 2020 +0300 description: Added necessary checks for obligatory grammar symbols. The issue was introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 14 +++++++++++++- src/test/njs_unit_test.c | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletions(-) diffs (67 lines): diff -r ea1754b79e7a -r 4117ec04714b src/njs_parser.c --- a/src/njs_parser.c Tue Jun 02 17:53:28 2020 +0300 +++ b/src/njs_parser.c Tue Jun 02 17:53:29 2020 +0300 @@ -888,6 +888,10 @@ static njs_int_t njs_parser_close_parenthesis(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) { return njs_parser_failed(parser); } @@ -1590,6 +1594,10 @@ njs_parser_array_after(njs_parser_t *par { njs_int_t ret; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + ret = njs_parser_array_item(parser, parser->target, parser->node); if (ret != NJS_OK) { return NJS_ERROR; @@ -1617,7 +1625,7 @@ static njs_int_t njs_parser_array_spread_element(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - if (token->type != NJS_TOKEN_CLOSE_BRACKET) { + if (parser->ret != NJS_OK || token->type != NJS_TOKEN_CLOSE_BRACKET) { return njs_parser_failed(parser); } @@ -6262,6 +6270,10 @@ njs_parser_catch_finally(njs_parser_t *p { njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + node = njs_parser_node_new(parser, NJS_TOKEN_FINALLY); if (node == NULL) { return NJS_ERROR; diff -r ea1754b79e7a -r 4117ec04714b src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 17:53:28 2020 +0300 +++ b/src/test/njs_unit_test.c Tue Jun 02 17:53:29 2020 +0300 @@ -16663,6 +16663,18 @@ static njs_unit_test_t njs_test[] = { njs_str("{name; {/ / /}"), njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("[(]"), + njs_str("SyntaxError: Unexpected token \"]\" in 1") }, + + { njs_str("[...]"), + njs_str("SyntaxError: Unexpected token \"]\" in 1") }, + + { njs_str("switch () {}"), + njs_str("SyntaxError: Unexpected token \")\" in 1") }, + + { njs_str("switch ([(]) {}"), + njs_str("SyntaxError: Unexpected token \"]\" in 1") }, }; From xeioex at nginx.com Tue Jun 2 15:18:06 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 02 Jun 2020 15:18:06 +0000 Subject: [njs] Fixed typo introduced in db77713e0536. Message-ID: details: https://hg.nginx.org/njs/rev/13e36f31e331 branches: changeset: 1416:13e36f31e331 user: Dmitry Volyntsev date: Tue Jun 02 14:59:27 2020 +0000 description: Fixed typo introduced in db77713e0536. diffstat: src/njs_array.c | 2 +- src/test/njs_unit_test.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletions(-) diffs (31 lines): diff -r 4117ec04714b -r 13e36f31e331 src/njs_array.c --- a/src/njs_array.c Tue Jun 02 17:53:29 2020 +0300 +++ b/src/njs_array.c Tue Jun 02 14:59:27 2020 +0000 @@ -1361,7 +1361,7 @@ njs_array_prototype_reverse(njs_vm_t *vm array->start[l] = hvalue; } else { - array->start[h] = njs_value_invalid; + array->start[l] = njs_value_invalid; } } else if (hret == NJS_OK) { diff -r 4117ec04714b -r 13e36f31e331 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 17:53:29 2020 +0300 +++ b/src/test/njs_unit_test.c Tue Jun 02 14:59:27 2020 +0000 @@ -4504,6 +4504,15 @@ static njs_unit_test_t njs_test[] = { njs_str("var a = [1,2,3,4]; a.reverse()"), njs_str("4,3,2,1") }, + { njs_str("[1,2,3,,,].reverse()"), + njs_str(",,3,2,1") }, + + { njs_str("[,2,3,,,].reverse()"), + njs_str(",,3,2,") }, + + { njs_str("[,,,3,2,1].reverse()"), + njs_str("1,2,3,,,") }, + { njs_str("var o = {1:true, 2:'', length:-2}; Array.prototype.reverse.call(o) === o"), njs_str("true") }, From xeioex at nginx.com Tue Jun 2 15:18:08 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 02 Jun 2020 15:18:08 +0000 Subject: [njs] Fixed endless loop in Array.prototype.sort(). Message-ID: details: https://hg.nginx.org/njs/rev/1ce9a0895630 branches: changeset: 1417:1ce9a0895630 user: Dmitry Volyntsev date: Tue Jun 02 14:59:30 2020 +0000 description: Fixed endless loop in Array.prototype.sort(). With non-consistent comparison function. The issue was introduced in 1d0825906438. diffstat: src/njs_utils.c | 7 +++---- src/test/njs_unit_test.c | 3 +++ 2 files changed, 6 insertions(+), 4 deletions(-) diffs (37 lines): diff -r 13e36f31e331 -r 1ce9a0895630 src/njs_utils.c --- a/src/njs_utils.c Tue Jun 02 14:59:27 2020 +0000 +++ b/src/njs_utils.c Tue Jun 02 14:59:30 2020 +0000 @@ -241,7 +241,7 @@ void njs_qsort(void *arr, size_t n, size_t esize, njs_sort_cmp_t cmp, void *ctx) { int r; - u_char *base, *lt, *gt, *p, *end; + u_char *base, *lt, *gt, *c, *p, *end; njs_uint_t m4; njs_swap_t swap; njs_qsort_state_t stack[NJS_MAX_DEPTH], *sp; @@ -321,9 +321,8 @@ njs_qsort(void *arr, size_t n, size_t es /* Insertion sort. */ for (p = base + esize; p < end; p += esize) { - while (p > base && cmp(p, p - esize, ctx) < 0) { - swap(p, p - esize, esize); - p -= esize; + for (c = p; c > base && cmp(c, c - esize, ctx) < 0; c -= esize) { + swap(c, c - esize, esize); } } } diff -r 13e36f31e331 -r 1ce9a0895630 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 14:59:27 2020 +0000 +++ b/src/test/njs_unit_test.c Tue Jun 02 14:59:30 2020 +0000 @@ -6101,6 +6101,9 @@ static njs_unit_test_t njs_test[] = "a.sort((a, b) => b.r - a.r).map(v=>v.n).join('')"), njs_str("BDEAC") }, + { njs_str("[1,2,3].sort(()=>-1)"), + njs_str("3,2,1") }, + { njs_str("var count = 0;" "[4,3,2,1].sort(function(x, y) { if (count++ == 2) {throw Error('Oops'); }; return x - y })"), njs_str("Error: Oops") }, From xeioex at nginx.com Tue Jun 2 15:18:10 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 02 Jun 2020 15:18:10 +0000 Subject: [njs] Ensuring Array.prototype.sort() stability. Message-ID: details: https://hg.nginx.org/njs/rev/c2fa0f18e58d branches: changeset: 1418:c2fa0f18e58d user: Dmitry Volyntsev date: Tue Jun 02 12:08:04 2020 +0000 description: Ensuring Array.prototype.sort() stability. For fast arrays with empty or undefined elements. This closes #312 issue on Github. diffstat: src/njs_array.c | 69 ++++++++++++++++++++++++----------------------- src/test/njs_unit_test.c | 6 ++++ 2 files changed, 41 insertions(+), 34 deletions(-) diffs (128 lines): diff -r 1ce9a0895630 -r c2fa0f18e58d src/njs_array.c --- a/src/njs_array.c Tue Jun 02 14:59:30 2020 +0000 +++ b/src/njs_array.c Tue Jun 02 12:08:04 2020 +0000 @@ -3216,8 +3216,8 @@ static njs_int_t njs_array_prototype_sort(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int64_t i, und, inv, len, nlen, length; - njs_int_t ret; + int64_t i, und, len, nlen, length; + njs_int_t ret, fast_path; njs_array_t *array; njs_value_t *this, *comparefn, *start, *strings; njs_array_sort_ctx_t ctx; @@ -3260,50 +3260,46 @@ njs_array_prototype_sort(njs_vm_t *vm, n ctx.strings.pointer = 0; ctx.exception = 0; - if (njs_fast_path(njs_is_fast_array(this))) { + fast_path = njs_is_fast_array(this); + + if (njs_fast_path(fast_path)) { array = njs_array(this); start = array->start; - /** - * Moving undefined and invalid elements to the end. - * x x x | undefineds | invalids - */ + slots = njs_mp_alloc(vm->mem_pool, + sizeof(njs_array_sort_slot_t) * length); + if (njs_slow_path(slots == NULL)) { + return NJS_ERROR; + } und = 0; - inv = length; - - for (i = length - 1; i >= 0; i--) { - if (njs_is_undefined(&start[i])) { - start[i] = start[inv - und - 1]; - start[inv - und - 1] = njs_value_undefined; + p = slots; + + for (i = 0; i < length; i++) { + if (njs_slow_path(!njs_is_valid(&start[i]))) { + fast_path = 0; + njs_mp_free(vm->mem_pool, slots); + slots = NULL; + goto slow_path; + } + + if (njs_slow_path(njs_is_undefined(&start[i]))) { und++; continue; } - if (!njs_is_valid(&start[i])) { - start[i] = start[inv - und - 1]; - start[inv - und - 1] = njs_value_undefined; - start[inv - 1] = njs_value_invalid; - inv--; - continue; - } + p->value = start[i]; + p->pos = i; + p->str = NULL; + p++; } - len = inv - und; - - slots = njs_mp_alloc(vm->mem_pool, - sizeof(njs_array_sort_slot_t) * len); - if (njs_slow_path(slots == NULL)) { - return NJS_ERROR; - } - - for (i = 0; i < len; i++) { - slots[i].value = start[i]; - slots[i].pos = i; - slots[i].str = NULL; - } + len = p - slots; } else { + +slow_path: + und = 0; p = NULL; end = NULL; @@ -3369,13 +3365,18 @@ njs_array_prototype_sort(njs_vm_t *vm, n goto exception; } - if (njs_fast_path(njs_is_fast_array(this))) { + if (njs_fast_path(fast_path)) { array = njs_array(this); start = array->start; + for (i = 0; i < len; i++) { start[i] = slots[i].value; } + for (i = len; und-- > 0; i++) { + start[i] = njs_value_undefined; + } + } else { for (i = 0; i < len; i++) { if (slots[i].pos != i) { diff -r 1ce9a0895630 -r c2fa0f18e58d src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 14:59:30 2020 +0000 +++ b/src/test/njs_unit_test.c Tue Jun 02 12:08:04 2020 +0000 @@ -6104,6 +6104,12 @@ static njs_unit_test_t njs_test[] = { njs_str("[1,2,3].sort(()=>-1)"), njs_str("3,2,1") }, + { njs_str("njs.dump([undefined,1,2,3].sort(()=>0))"), + njs_str("[1,2,3,undefined]") }, + + { njs_str("njs.dump([1,,2,3].sort(()=>0))"), + njs_str("[1,2,3,]") }, + { njs_str("var count = 0;" "[4,3,2,1].sort(function(x, y) { if (count++ == 2) {throw Error('Oops'); }; return x - y })"), njs_str("Error: Oops") }, From alexander.borisov at nginx.com Wed Jun 3 12:18:35 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 03 Jun 2020 12:18:35 +0000 Subject: [njs] Removed support for functions in labelled statements. Message-ID: details: https://hg.nginx.org/njs/rev/4737eb75961e branches: changeset: 1419:4737eb75961e user: Alexander Borisov date: Wed Jun 03 15:17:51 2020 +0300 description: Removed support for functions in labelled statements. In strict mode, support for functions is prohibited. The issue was introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 13 +++---------- src/test/njs_unit_test.c | 3 +++ 2 files changed, 6 insertions(+), 10 deletions(-) diffs (43 lines): diff -r c2fa0f18e58d -r 4737eb75961e src/njs_parser.c --- a/src/njs_parser.c Tue Jun 02 12:08:04 2020 +0000 +++ b/src/njs_parser.c Wed Jun 03 15:17:51 2020 +0300 @@ -5976,7 +5976,6 @@ njs_parser_labelled_statement(njs_parser { uintptr_t unique_id; njs_variable_t *label; - njs_parser_node_t *node; unique_id = token->unique_id; @@ -6002,15 +6001,9 @@ njs_parser_labelled_statement(njs_parser parser->node = NULL; if (token->type == NJS_TOKEN_FUNCTION) { - node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION); - if (node == NULL) { - return NJS_ERROR; - } - - node->token_line = token->line; - - njs_lexer_consume_token(parser->lexer, 1); - njs_parser_next(parser, njs_parser_function_declaration); + njs_syntax_error(parser->vm, "In strict mode code, functions can only " + "be declared at top level or inside a block."); + return NJS_DONE; } else { njs_parser_next(parser, njs_parser_statement_wo_node); diff -r c2fa0f18e58d -r 4737eb75961e src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 02 12:08:04 2020 +0000 +++ b/src/test/njs_unit_test.c Wed Jun 03 15:17:51 2020 +0300 @@ -2934,6 +2934,9 @@ static njs_unit_test_t njs_test[] = { njs_str("a:{continue b}"), njs_str("SyntaxError: Undefined label \"b\" in 1") }, + { njs_str("a:function name() {}"), + njs_str("SyntaxError: In strict mode code, functions can only be declared at top level or inside a block.") }, + #if 0 /* TODO */ { njs_str("a:{1; break a}"), njs_str("1") }, From mdounin at mdounin.ru Wed Jun 3 16:22:42 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 03 Jun 2020 16:22:42 +0000 Subject: [nginx] SSL: added verify callback to ngx_ssl_trusted_certificate(). Message-ID: details: https://hg.nginx.org/nginx/rev/699f6e55bbb4 branches: changeset: 7664:699f6e55bbb4 user: Maxim Dounin date: Wed Jun 03 19:11:32 2020 +0300 description: SSL: added verify callback to ngx_ssl_trusted_certificate(). This ensures that certificate verification is properly logged to debug log during upstream server certificate verification. This should help with debugging various certificate issues. diffstat: src/event/ngx_event_openssl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff -r 7cbf6389194b -r 699f6e55bbb4 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Mon Jun 01 22:31:23 2020 +0300 +++ b/src/event/ngx_event_openssl.c Wed Jun 03 19:11:32 2020 +0300 @@ -920,6 +920,8 @@ ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) { + SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback); + SSL_CTX_set_verify_depth(ssl->ctx, depth); if (cert->len == 0) { From alexander.borisov at nginx.com Wed Jun 3 17:50:33 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Wed, 03 Jun 2020 17:50:33 +0000 Subject: [njs] Fixed parsing of invalid unary expression. Message-ID: details: https://hg.nginx.org/njs/rev/61dce54ce3d5 branches: changeset: 1420:61dce54ce3d5 user: Alexander Borisov date: Wed Jun 03 20:49:52 2020 +0300 description: Fixed parsing of invalid unary expression. The issue was introduced in 86f55a7dc4a4. diffstat: src/njs_parser.c | 6 +++++- src/test/njs_unit_test.c | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletions(-) diffs (57 lines): diff -r 4737eb75961e -r 61dce54ce3d5 src/njs_parser.c --- a/src/njs_parser.c Wed Jun 03 15:17:51 2020 +0300 +++ b/src/njs_parser.c Wed Jun 03 20:49:52 2020 +0300 @@ -3304,7 +3304,7 @@ njs_parser_unary_expression(njs_parser_t parser->target = node; - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, node, 0, njs_parser_unary_expression_next); } @@ -3332,6 +3332,10 @@ njs_parser_unary_expression_next(njs_par njs_token_type_t type; njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + type = parser->target->token_type; node = parser->node; diff -r 4737eb75961e -r 61dce54ce3d5 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Jun 03 15:17:51 2020 +0300 +++ b/src/test/njs_unit_test.c Wed Jun 03 20:49:52 2020 +0300 @@ -16696,6 +16696,30 @@ static njs_unit_test_t njs_test[] = { njs_str("switch ([(]) {}"), njs_str("SyntaxError: Unexpected token \"]\" in 1") }, + + { njs_str("{{}{-}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{+}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{delete}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{++}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{++1}"), + njs_str("ReferenceError: Invalid left-hand side in prefix operation in 1") }, + + { njs_str("{{}{1++}"), + njs_str("ReferenceError: Invalid left-hand side in postfix operation in 1") }, + + { njs_str("{{}{1/}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{1>>}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, }; From xeioex at nginx.com Wed Jun 3 18:41:12 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 03 Jun 2020 18:41:12 +0000 Subject: [njs] Introduced njs_array_copy_within(). Message-ID: details: https://hg.nginx.org/njs/rev/a23651137ccf branches: changeset: 1421:a23651137ccf user: Dmitry Volyntsev date: Wed Jun 03 18:40:09 2020 +0000 description: Introduced njs_array_copy_within(). diffstat: src/njs_array.c | 105 +++++++++++++++++++++++++--------------------- src/test/njs_unit_test.c | 7 +++ 2 files changed, 64 insertions(+), 48 deletions(-) diffs (157 lines): diff -r 61dce54ce3d5 -r a23651137ccf src/njs_array.c --- a/src/njs_array.c Wed Jun 03 20:49:52 2020 +0300 +++ b/src/njs_array.c Wed Jun 03 18:40:09 2020 +0000 @@ -250,6 +250,60 @@ done: } +static njs_int_t +njs_array_copy_within(njs_vm_t *vm, njs_value_t *array, int64_t to_pos, + int64_t from_pos, int64_t count, njs_bool_t forward) +{ + int64_t i, from, to; + njs_int_t ret; + njs_array_t *arr; + njs_value_t value; + + if (njs_fast_path(njs_is_fast_array(array) && count > 0)) { + arr = njs_array(array); + + memmove(&arr->start[to_pos], &arr->start[from_pos], + count * sizeof(njs_value_t)); + + return NJS_OK; + } + + if (!forward) { + from_pos += count - 1; + to_pos += count - 1; + } + + for (i = 0; i < count; i++) { + if (forward) { + from = from_pos + i; + to = to_pos + i; + + } else { + from = from_pos - i; + to = to_pos - i; + } + + ret = njs_value_property_i64(vm, array, from, &value); + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + + if (ret == NJS_OK) { + ret = njs_value_property_i64_set(vm, array, to, &value); + + } else { + ret = njs_value_property_i64_delete(vm, array, to, NULL); + } + + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + } + + return NJS_OK; +} + + njs_int_t njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value) { @@ -3423,11 +3477,9 @@ static njs_int_t njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int8_t direction; int64_t length, count, to, from, end; njs_int_t ret; - njs_array_t *array; - njs_value_t *this, *value, prop; + njs_value_t *this, *value; this = njs_argument(args, 0); @@ -3471,53 +3523,10 @@ njs_array_prototype_copy_within(njs_vm_t count = njs_min(end - from, length - to); - if (from < to && from + count) { - direction = -1; - from = from + count - 1; - to = to + count - 1; - - } else { - direction = 1; - } - njs_vm_retval_set(vm, this); - if (njs_fast_path(njs_is_fast_array(this))) { - array = njs_array(this); - - while (count-- > 0) { - array->start[to] = array->start[from]; - - from = from + direction; - to = to + direction; - } - - return NJS_OK; - } - - while (count-- > 0) { - ret = njs_value_property_i64(vm, this, from, &prop); - - if (ret == NJS_OK) { - ret = njs_value_property_i64_set(vm, this, to, &prop); - - } else { - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - - ret = njs_value_property_i64_delete(vm, this, to, NULL); - } - - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - - from = from + direction; - to = to + direction; - } - - return NJS_OK; + return njs_array_copy_within(vm, this, to, from, count, + !(from < to && to < from + count)); } diff -r 61dce54ce3d5 -r a23651137ccf src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Jun 03 20:49:52 2020 +0300 +++ b/src/test/njs_unit_test.c Wed Jun 03 18:40:09 2020 +0000 @@ -4165,6 +4165,9 @@ static njs_unit_test_t njs_test[] = { njs_str("[0, 1, , , 1].copyWithin(0, 1, 4)"), njs_str("1,,,,1") }, + { njs_str("[0, 1, 2, 3].copyWithin(0, 1, -10)"), + njs_str("0,1,2,3") }, + { njs_str("var o = [0, 1, , , 1].copyWithin(0, 1, 4); typeof o"), njs_str("object") }, @@ -4184,6 +4187,10 @@ static njs_unit_test_t njs_test[] = "Object.keys(obj) + '|' + Object.values(obj)"), njs_str("length,1,2,3,4,5,0|5,a,b,c,d,e,c") }, + { njs_str("var o = {length:1}; Object.defineProperty(o, '0', {get:()=>{throw Error('Oops')}});" + "Array.prototype.copyWithin.call(o, 0, 0)"), + njs_str("Error: Oops") }, + { njs_str("Array.prototype.slice(1)"), njs_str("") }, From xeioex at nginx.com Wed Jun 3 18:41:14 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 03 Jun 2020 18:41:14 +0000 Subject: [njs] Fixed Array.prototype.splice() according to the specification. Message-ID: details: https://hg.nginx.org/njs/rev/c1e3fd0d24fd branches: changeset: 1422:c1e3fd0d24fd user: Dmitry Volyntsev date: Wed Jun 03 18:40:10 2020 +0000 description: Fixed Array.prototype.splice() according to the specification. diffstat: src/njs_array.c | 171 ++++++++++++++++++++++++++++------------------ src/test/njs_unit_test.c | 96 ++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 66 deletions(-) diffs (319 lines): diff -r a23651137ccf -r c1e3fd0d24fd src/njs_array.c --- a/src/njs_array.c Wed Jun 03 18:40:09 2020 +0000 +++ b/src/njs_array.c Wed Jun 03 18:40:10 2020 +0000 @@ -1241,10 +1241,9 @@ static njs_int_t njs_array_prototype_splice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int64_t n, start, length, items, delta, delete; + int64_t i, n, start, length, items, delta, delete; njs_int_t ret; - njs_uint_t i; - njs_value_t *this; + njs_value_t *this, value, del_object; njs_array_t *array, *deleted; this = njs_argument(args, 0); @@ -1254,74 +1253,81 @@ njs_array_prototype_splice(njs_vm_t *vm, return ret; } - if (njs_slow_path(!njs_is_fast_array(this))) { - njs_internal_error(vm, "splice() is not implemented yet for objects"); + ret = njs_object_length(vm, this, &length); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length); + + items = 0; + delete = 0; + + if (nargs == 2) { + delete = length - start; + + } else if (nargs > 2) { + items = nargs - 3; + + ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &delete); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + delete = njs_min(njs_max(delete, 0), length - start); + } + + delta = items - delete; + + if (njs_slow_path((length + delta) > NJS_MAX_LENGTH)) { + njs_type_error(vm, "Invalid length"); return NJS_ERROR; } - array = NULL; - start = 0; - delete = 0; - - if (njs_is_fast_array(this)) { - array = njs_array(this); - length = array->length; - - if (nargs > 1) { - ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - if (start < 0) { - start += length; - - if (start < 0) { - start = 0; - } - - } else if (start > length) { - start = length; - } - - delete = length - start; - - if (nargs > 2) { - ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &n); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - if (n < 0) { - delete = 0; - - } else if (n < delete) { - delete = n; - } - } - } - } + /* TODO: ArraySpeciesCreate(). */ deleted = njs_array_alloc(vm, 0, delete, 0); if (njs_slow_path(deleted == NULL)) { return NJS_ERROR; } - if (njs_slow_path(!deleted->object.fast_array)) { - njs_internal_error(vm, "deleted is not a fast_array"); - return NJS_ERROR; - } - - if (array != NULL && (delete >= 0 || nargs > 3)) { - - /* Move deleted items to a new array to return. */ - for (i = 0, n = start; i < (njs_uint_t) delete; i++, n++) { - /* No retention required. */ + if (njs_fast_path(njs_is_fast_array(this) && deleted->object.fast_array)) { + array = njs_array(this); + for (i = 0, n = start; i < delete; i++, n++) { deleted->start[i] = array->start[n]; } - items = (nargs > 3) ? nargs - 3: 0; - delta = items - delete; + } else { + njs_set_array(&del_object, deleted); + + for (i = 0, n = start; i < delete; i++, n++) { + ret = njs_value_property_i64(vm, this, n, &value); + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + + if (ret == NJS_OK) { + /* TODO: CreateDataPropertyOrThrow(). */ + ret = njs_value_property_i64_set(vm, &del_object, i, &value); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + } + } + + ret = njs_object_length_set(vm, &del_object, delete); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + } + + if (njs_fast_path(njs_is_fast_array(this))) { + array = njs_array(this); if (delta != 0) { /* @@ -1335,18 +1341,51 @@ njs_array_prototype_splice(njs_vm_t *vm, } } - memmove(&array->start[start + items], &array->start[n], - (array->length - n) * sizeof(njs_value_t)); + ret = njs_array_copy_within(vm, this, start + items, start + delete, + array->length - (start + delete), 0); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } array->length += delta; } /* Copy new items. */ - n = start; - - for (i = 3; i < nargs; i++) { - /* GC: njs_retain(&args[i]); */ - array->start[n++] = args[i]; + + if (items > 0) { + memcpy(&array->start[start], &args[3], + items * sizeof(njs_value_t)); + } + + } else { + + if (delta != 0) { + ret = njs_array_copy_within(vm, this, start + items, start + delete, + length - (start + delete), delta < 0); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + for (i = length - 1; i >= length + delta; i--) { + ret = njs_value_property_i64_delete(vm, this, i, NULL); + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + } + } + + /* Copy new items. */ + + for (i = 3, n = start; items-- > 0; i++, n++) { + ret = njs_value_property_i64_set(vm, this, n, &args[i]); + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + } + + ret = njs_object_length_set(vm, this, length + delta); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; } } diff -r a23651137ccf -r c1e3fd0d24fd src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Jun 03 18:40:09 2020 +0000 +++ b/src/test/njs_unit_test.c Wed Jun 03 18:40:10 2020 +0000 @@ -4499,6 +4499,102 @@ static njs_unit_test_t njs_test[] = "a.splice(3, 2, 8, 9, 10, 11 ).join(':') + '|' + a"), njs_str("3:4|0,1,2,8,9,10,11,5,6,7") }, + { njs_str("[" + " []," + " [1]," + " [1, 2]," + " [1, 2, 'a']," + " [1, 2, 'a', 'b']," + " [1, 2, 'a', 'b', 'c']," + "]" + ".map(args=>{var a = [0,1,3,4,5]; a.splice.apply(a, args); return a})" + ".map(v=>v.join(''))"), + njs_str("01345,0,045,0a45,0ab45,0abc45") }, + + { njs_str("[" + " []," + " [1]," + " [1, 1, 'a']," + " [1, 2, 'a']," + " [1, 2, 'a', 'b']," + " [1, 2, 'a', 'b', 'c']," + "]" + ".map(args=>{var a = [0,1,3,4,5]; return a.splice.apply(a, args);})" + ".map(v=>v.join(''))"), + njs_str(",1345,1,13,13,13") }, + + { njs_str("Object.prototype.splice = Array.prototype.splice;" + "Object.prototype.join = Array.prototype.join;" + "[" + " []," + " [1]," + " [1, 2]," + " [1, 1, 'a']," + " [1, 2, 'a']," + " [1, 2, 'a', 'b']," + " [1, 2, 'a', 'b', 'c']," + "]" + ".map(args=>{var a = {0:0, 1:1, 2:3, 3:4, 4:5, length:5};" + " a.splice.apply(a, args); return a})" + ".map(v=>v.join(''))"), + njs_str("01345,0,045,0a345,0a45,0ab45,0abc45") }, + + { njs_str("Object.prototype.splice = Array.prototype.splice;" + "Object.prototype.join = Array.prototype.join;" + "[" + " []," + " [1]," + " [1, 0, 'a']," + " [1, 1, 'a']," + " [1, 2, 'a']," + " [1, 2, 'a', 'b']," + " [1, 2, 'a', 'b', 'c']," + "]" + ".map(args=>{var a = {0:0, 1:1, 2:3, 3:4, 4:5, length:5};" + " return a.splice.apply(a, args);})" + ".map(v=>v.join(''))"), + njs_str(",1345,,1,13,13,13") }, + + { njs_str("Array.prototype.splice.call({0:0,1:1,2:2,3:3,length:4},0,3,4,5)"), + njs_str("0,1,2") }, + + { njs_str("var obj = {0:0,1:1,2:2,3:3,length:4};" + "Array.prototype.splice.call(obj,0,3,4,5); obj[3]"), + njs_str("undefined") }, + + { njs_str("var obj = {4294967294: 'x', length:-1};" + "Array.prototype.splice.call(obj, 4294967294, 1); obj.length"), + njs_str("0") }, + + { njs_str("var obj = {0:0, 1:1, 2:2};" + "Object.defineProperty(obj, 'length', {value:3, writable:false});" + "Array.prototype.splice.call(obj, 1, 2, 4)"), + njs_str("TypeError: Cannot assign to read-only property \"length\" of object") }, + + { njs_str("var obj = {'9007199254740988': 'A', '9007199254740989': 'B'," + " '9007199254740990': 'C', '9007199254740991': 'D', " + " length: 2 ** 53 + 2};" + "Array.prototype.splice.call(obj, 2**53-3, 2 ** 53 + 4)"), + njs_str("B,C") }, + + { njs_str("var obj = {'9007199254740988': 'A', '9007199254740989': 'B'," + " '9007199254740990': 'C', '9007199254740991': 'D', " + " length: 2 ** 53 + 2};" + "Array.prototype.splice.call(obj, 2**53-3, 2 ** 53 + 4);" + "obj['9007199254740988'] == 'A' && obj['9007199254740991'] == 'D'"), + njs_str("true") }, + + { njs_str("var obj = {'9007199254740990': 'A', '9007199254740991': 'B'," + " length: 2 ** 53 - 1};" + "Array.prototype.splice.call(obj, 2**53-2, 1, 'C');" + "obj['9007199254740990'] == 'C' && obj['9007199254740991'] == 'B'"), + njs_str("true") }, + + { njs_str("var obj = {'9007199254740990': 'A', '9007199254740991': 'B'," + " length: 2 ** 53 - 1};" + "Array.prototype.splice.call(obj, 2**53-2, 0, 'C');"), + njs_str("TypeError: Invalid length") }, + { njs_str("var a = []; a.reverse()"), njs_str("") }, From yigal.edery at kameleonsec.com Thu Jun 4 17:53:50 2020 From: yigal.edery at kameleonsec.com (Yigal Edery) Date: Thu, 4 Jun 2020 17:53:50 +0000 Subject: nginx test plan with max coverage? Message-ID: Hi I hope this is the right forum to ask. I need to set up NGINX and run a full test coverage on it. Other than the nginx-tests, is there some formal test plan for nginx that you use, to exercises an nginx server before declaring a release? I am thinking some long duration tests with maximum code coverage and stability tests... Thanks, Yigal -------------- next part -------------- An HTML attachment was scrubbed... URL: From sander at hoentjen.eu Fri Jun 5 07:59:33 2020 From: sander at hoentjen.eu (Sander Hoentjen) Date: Fri, 5 Jun 2020 09:59:33 +0200 Subject: [PATCH] Added support for proxying managesieve protocol In-Reply-To: References: <58016a3a-c11d-bb31-2b05-916cb8124598@hoentjen.eu> <89afc309-4185-e0a1-d6d3-e9f25f65235a@hoentjen.eu> <911a2e90-5002-3e1c-eb9a-6be3f4e329fc@nginx.com> Message-ID: <02875675-7ac0-7aad-cd71-6c741872ee6b@hoentjen.eu> Polite bump, I hope someone has time to look at it now :) Kind regards, Sander On 4/16/20 7:49 PM, Sander Hoentjen wrote: > Hi Maxim, > > Thanks for your response! I will wait till you have time to properly > review my code. That is more important than getting it in fast. > > The code is available at > https://github.com/AntagonistHQ/nginx/tree/sieve_v2, so at least it is > out in the public for anyone interested. > > For now, I'll just wait and see what will happen in May. > > Thank you, > > Sander > > > On 4/15/20 8:56 PM, Maxim Konovalov wrote: >> Hi Sander, >> >> First of all, thanks for your code contribution and your work done on >> it. >> >> Among with other tasks we are now in a preparation for a new development >> branch 1.19 and don't have much developers resources to make a proper >> review of the code. >> >> I'd suggest to put the module somewhere on external repo for now, e.g. >> on github.? I hope we'll be able to return to this topic later in May. >> >> Thanks, >> >> Maxim >> >> On 14.04.2020 21:27, Sander Hoentjen wrote: >>> Hello list, >>> >>> Since the Nginx development procedure is unknown to me: Did i do the >>> right things to get my submission to be considered? What are the next >>> steps? Will somebody review this, or reject it? Or is it possible that >>> it just won't get any attention, and that this will mean it will not be >>> considered? I hope I will at least get some feedback, even if it is a >>> rejection :) >>> >>> Kind regards, >>> >>> Sander >>> >>> On 4/8/20 8:33 PM, Sander Hoentjen wrote: >>>> Hello list, >>>> >>>> This is my attempt at adding support for the managesieve protocol. I >>>> hope this is something that you would consider to add. Comments on the >>>> code are very welcome! Also, I hope I submitted this the right way. If >>>> I need to change anything, please let me know. >>>> >>>> Kind regards, >>>> >>>> Sander Hoentjen >>>> >>>> On 4/8/20 8:26 PM, Sander Hoentjen wrote: >>>>> # HG changeset patch >>>>> # User Sander Hoentjen >>>>> # Date 1586369831 -7200 >>>>> # Wed Apr 08 20:17:11 2020 +0200 >>>>> # Node ID f1dffaf619688aaab90caf31781ebe27c3f79598 >>>>> # Parent 0cb942c1c1aa98118076e72e0b89940e85e6291c >>>>> Added support for proxying managesieve protocol >>>>> >> [...] >> >> > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > From xeioex at nginx.com Fri Jun 5 11:59:54 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Jun 2020 11:59:54 +0000 Subject: [njs] Fixed AST printing with long strings values. Message-ID: details: https://hg.nginx.org/njs/rev/43de01740782 branches: changeset: 1423:43de01740782 user: Dmitry Volyntsev date: Fri Jun 05 11:40:42 2020 +0000 description: Fixed AST printing with long strings values. The issue was introduced in d255e73aed3b. diffstat: src/njs_parser.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diffs (20 lines): diff -r c1e3fd0d24fd -r 43de01740782 src/njs_parser.c --- a/src/njs_parser.c Wed Jun 03 18:40:10 2020 +0000 +++ b/src/njs_parser.c Fri Jun 05 11:40:42 2020 +0000 @@ -8368,12 +8368,14 @@ njs_parser_serialize_tree(njs_chb_t *cha njs_parser_serialize_indent(chain, indent); if (node->token_type == NJS_TOKEN_NUMBER) { - njs_chb_sprintf(chain, 32, " \"value\": %f\n", + njs_chb_sprintf(chain, 32, " \"value\": %f", njs_number(&node->u.value)); } else { njs_string_get(&node->u.value, &str); - njs_chb_sprintf(chain, 32, " \"value\": \"%V\"\n", &str); + njs_chb_append_literal(chain, " \"value\": \""); + njs_chb_append_str(chain, &str); + njs_chb_append_literal(chain, "\""); } break; From xeioex at nginx.com Fri Jun 5 11:59:56 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Jun 2020 11:59:56 +0000 Subject: [njs] Added %TypedArray%.prototype.sort(). Message-ID: details: https://hg.nginx.org/njs/rev/23df5a31bafd branches: changeset: 1424:23df5a31bafd user: Dmitry Volyntsev date: Fri Jun 05 11:42:40 2020 +0000 description: Added %TypedArray%.prototype.sort(). diffstat: src/njs_typed_array.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 31 ++++ 2 files changed, 365 insertions(+), 0 deletions(-) diffs (392 lines): diff -r 43de01740782 -r 23df5a31bafd src/njs_typed_array.c --- a/src/njs_typed_array.c Fri Jun 05 11:40:42 2020 +0000 +++ b/src/njs_typed_array.c Fri Jun 05 11:42:40 2020 +0000 @@ -813,6 +813,332 @@ njs_typed_array_prototype_copy_within(nj } +static int +njs_typed_array_compare_i8(const void *a, const void *b, void *c) +{ + return *((const int8_t *) a) - *((const int8_t *) b); +} + + +static int +njs_typed_array_compare_u8(const void *a, const void *b, void *c) +{ + return *((const uint8_t *) a) - *((const uint8_t *) b); +} + + +static int +njs_typed_array_compare_i16(const void *a, const void *b, void *c) +{ + return *((const int16_t *) a) - *((const int16_t *) b); +} + + +static int +njs_typed_array_compare_u16(const void *a, const void *b, void *c) +{ + return *((const uint16_t *) a) - *((const uint16_t *) b); +} + + +static int +njs_typed_array_compare_i32(const void *a, const void *b, void *c) +{ + int32_t ai, bi; + + ai = *(const int32_t *) a; + bi = *(const int32_t *) b; + + return (ai > bi) - (ai < bi); +} + + +static int +njs_typed_array_compare_u32(const void *a, const void *b, void *c) +{ + uint32_t au, bu; + + au = *(const uint32_t *) a; + bu = *(const uint32_t *) b; + + return (au > bu) - (au < bu); +} + + +njs_inline int +njs_typed_array_compare(double a, double b) +{ + if (njs_slow_path(isnan(a))) { + if (isnan(b)) { + return 0; + } + + return 1; + } + + if (njs_slow_path(isnan(b))) { + return -1; + } + + if (a < b) { + return -1; + } + + if (a > b) { + return 1; + } + + return signbit(b) - signbit(a); +} + + +static int +njs_typed_array_compare_f32(const void *a, const void *b, void *c) +{ + return njs_typed_array_compare(*(const float *) a, *(const float *) b); +} + + +static int +njs_typed_array_compare_f64(const void *a, const void *b, void *c) +{ + return njs_typed_array_compare(*(const double *) a, *(const double *) b); +} + + +static double +njs_typed_array_get_u8(const void *a) +{ + return *(const uint8_t *) a; +} + + +static double +njs_typed_array_get_i8(const void *a) +{ + return *(const int8_t *) a; +} + + +static double +njs_typed_array_get_u16(const void *a) +{ + return *(const uint16_t *) a; +} + + +static double +njs_typed_array_get_i16(const void *a) +{ + return *(const int16_t *) a; +} + + +static double +njs_typed_array_get_u32(const void *a) +{ + return *(const uint32_t *) a; +} + + +static double +njs_typed_array_get_i32(const void *a) +{ + return *(const int32_t *) a; +} + + +static double +njs_typed_array_get_f32(const void *a) +{ + return *(const float *) a; +} + + +static double +njs_typed_array_get_f64(const void *a) +{ + return *(const double *) a; +} + + +typedef struct { + njs_vm_t *vm; + njs_function_t *function; + njs_bool_t exception; + double (*get)(const void *v); +} njs_typed_array_sort_ctx_t; + +typedef int (*njs_typed_array_cmp_t)(const void *, const void *, void *ctx); + + +static int +njs_typed_array_generic_compare(const void *a, const void *b, void *c) +{ + double num; + njs_int_t ret; + njs_value_t arguments[3], retval; + njs_typed_array_sort_ctx_t *ctx; + + ctx = c; + + if (njs_slow_path(ctx->exception)) { + return 0; + } + + njs_set_undefined(&arguments[0]); + njs_set_number(&arguments[1], ctx->get(a)); + njs_set_number(&arguments[2], ctx->get(b)); + + ret = njs_function_apply(ctx->vm, ctx->function, arguments, 3, &retval); + if (njs_slow_path(ret != NJS_OK)) { + goto exception; + } + + ret = njs_value_to_number(ctx->vm, &retval, &num); + if (njs_slow_path(ret != NJS_OK)) { + goto exception; + } + + if (njs_slow_path(isnan(num))) { + return 0; + } + + if (num != 0) { + return (num > 0) - (num < 0); + } + + return 0; + +exception: + + ctx->exception = 1; + + return 0; +} + + +static njs_int_t +njs_typed_array_prototype_sort(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + u_char *base, *orig; + int64_t length; + uint32_t element_size; + njs_value_t *this, *comparefn; + njs_typed_array_t *array; + njs_array_buffer_t *buffer; + njs_typed_array_cmp_t cmp; + njs_typed_array_sort_ctx_t ctx; + + this = njs_argument(args, 0); + if (njs_slow_path(!njs_is_typed_array(this))) { + njs_type_error(vm, "this is not a typed array"); + return NJS_ERROR; + } + + ctx.vm = vm; + ctx.exception = 0; + + comparefn = njs_arg(args, nargs, 1); + + if (njs_is_defined(comparefn)) { + if (njs_slow_path(!njs_is_function(comparefn))) { + njs_type_error(vm, "comparefn must be callable or undefined"); + return NJS_ERROR; + } + + ctx.function = njs_function(comparefn); + + } else { + ctx.function = NULL; + } + + array = njs_typed_array(this); + + switch (array->type) { + case NJS_OBJ_TYPE_UINT8_ARRAY: + case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY: + cmp = njs_typed_array_compare_u8; + ctx.get = njs_typed_array_get_u8; + break; + + case NJS_OBJ_TYPE_INT8_ARRAY: + cmp = njs_typed_array_compare_i8; + ctx.get = njs_typed_array_get_i8; + break; + + case NJS_OBJ_TYPE_UINT16_ARRAY: + cmp = njs_typed_array_compare_u16; + ctx.get = njs_typed_array_get_u16; + break; + + case NJS_OBJ_TYPE_INT16_ARRAY: + cmp = njs_typed_array_compare_i16; + ctx.get = njs_typed_array_get_i16; + break; + + case NJS_OBJ_TYPE_UINT32_ARRAY: + cmp = njs_typed_array_compare_u32; + ctx.get = njs_typed_array_get_u32; + break; + + case NJS_OBJ_TYPE_INT32_ARRAY: + cmp = njs_typed_array_compare_i32; + ctx.get = njs_typed_array_get_i32; + break; + + case NJS_OBJ_TYPE_FLOAT32_ARRAY: + cmp = njs_typed_array_compare_f32; + ctx.get = njs_typed_array_get_f32; + break; + + default: + + /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */ + + cmp = njs_typed_array_compare_f64; + ctx.get = njs_typed_array_get_f64; + break; + } + + length = njs_typed_array_length(array); + buffer = njs_typed_array_buffer(array); + element_size = njs_typed_array_element_size(array->type); + base = &buffer->u.u8[array->offset * element_size]; + orig = base; + + if (ctx.function != NULL) { + cmp = njs_typed_array_generic_compare; + base = njs_mp_alloc(vm->mem_pool, length * element_size); + if (njs_slow_path(base == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + memcpy(base, &buffer->u.u8[array->offset * element_size], + length * element_size); + } + + njs_qsort(base, length, element_size, cmp, &ctx); + if (ctx.function != NULL) { + if (&buffer->u.u8[array->offset * element_size] == orig) { + memcpy(orig, base, length * element_size); + } + + njs_mp_free(vm->mem_pool, base); + } + + if (njs_slow_path(ctx.exception)) { + return NJS_ERROR; + } + + njs_set_typed_array(&vm->retval, array); + + return NJS_OK; +} + + njs_int_t njs_typed_array_to_chain(njs_vm_t *vm, njs_chb_t *chain, njs_typed_array_t *array, njs_value_t *sep) @@ -1052,6 +1378,14 @@ static const njs_object_prop_t njs_type { .type = NJS_PROPERTY, + .name = njs_string("sort"), + .value = njs_native_function(njs_typed_array_prototype_sort, 1), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, .name = njs_string("copyWithin"), .value = njs_native_function(njs_typed_array_prototype_copy_within, 2), .writable = 1, diff -r 43de01740782 -r 23df5a31bafd src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Jun 05 11:40:42 2020 +0000 +++ b/src/test/njs_unit_test.c Fri Jun 05 11:42:40 2020 +0000 @@ -5719,6 +5719,37 @@ static njs_unit_test_t njs_test[] = " return a.toString() === '1,2,3,3'})"), njs_str("true") }, + { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var a = new v([]); a.sort(); " + " return a.toString() === ''})"), + njs_str("true") }, + + { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var a = new v([5]); a.sort(); " + " return a.toString() === '5'})"), + njs_str("true") }, + + { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var a = new v([3,3,2,1]); a.sort(); " + " return a.toString() === '1,2,3,3'})"), + njs_str("true") }, + + { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var a = new v([3,3,2,1]); a.sort((x,y)=>x-y); " + " return a.toString() === '1,2,3,3'})"), + njs_str("true") }, + + { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var a = (new v([255,255,3,3,2,1])).slice(2); a.sort(); " + " return a.toString() === '1,2,3,3'})"), + njs_str("true") }, + + { njs_str("(new Float32Array([255,255,NaN,3,NaN,Infinity,3,-Infinity,0,-0,2,1,-5])).slice(2).sort()"), + njs_str("-Infinity,-5,0,0,1,2,3,3,Infinity,NaN,NaN") }, + + { njs_str("(new Float64Array([255,255,NaN,3,NaN,Infinity,3,-Infinity,0,-0,2,1,-5])).slice(2).sort()"), + njs_str("-Infinity,-5,0,0,1,2,3,3,Infinity,NaN,NaN") }, + #if NJS_HAVE_LARGE_STACK { njs_str("var o = Object({length: 3});" "Object.defineProperty(o, '0', {set: function(v){this[0] = 2 * v}});" From xeioex at nginx.com Fri Jun 5 11:59:58 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 05 Jun 2020 11:59:58 +0000 Subject: [njs] Fixed %TypedArray%.prototype.copyWithin() with nonzero byte offset. Message-ID: details: https://hg.nginx.org/njs/rev/790bde011274 branches: changeset: 1425:790bde011274 user: Dmitry Volyntsev date: Fri Jun 05 11:42:41 2020 +0000 description: Fixed %TypedArray%.prototype.copyWithin() with nonzero byte offset. diffstat: src/njs_typed_array.c | 4 ++-- src/test/njs_unit_test.c | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diffs (31 lines): diff -r 23df5a31bafd -r 790bde011274 src/njs_typed_array.c --- a/src/njs_typed_array.c Fri Jun 05 11:42:40 2020 +0000 +++ b/src/njs_typed_array.c Fri Jun 05 11:42:41 2020 +0000 @@ -803,8 +803,8 @@ njs_typed_array_prototype_copy_within(nj buffer = njs_typed_array_buffer(array); element_size = njs_typed_array_element_size(array->type); - to = to * element_size; - from = from * element_size; + to = (to + array->offset) * element_size; + from = (from + array->offset) * element_size; count = count * element_size; memmove(&buffer->u.u8[to], &buffer->u.u8[from], count); diff -r 23df5a31bafd -r 790bde011274 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Jun 05 11:42:40 2020 +0000 +++ b/src/test/njs_unit_test.c Fri Jun 05 11:42:41 2020 +0000 @@ -5720,6 +5720,13 @@ static njs_unit_test_t njs_test[] = njs_str("true") }, { njs_str(NJS_TYPED_ARRAY_LIST + ".every(v=>{var orig = new v([255,255,1,2,3,4,5]);" + " var a = new v(orig.buffer, 2* v.BYTES_PER_ELEMENT);" + " a.copyWithin(0,3);" + " return a.toString() === '4,5,3,4,5'})"), + njs_str("true") }, + + { njs_str(NJS_TYPED_ARRAY_LIST ".every(v=>{var a = new v([]); a.sort(); " " return a.toString() === ''})"), njs_str("true") }, From svetlightsm at mail.ru Fri Jun 5 12:06:31 2020 From: svetlightsm at mail.ru (svetlightsm at mail.ru) Date: Fri, 05 Jun 2020 15:06:31 +0300 Subject: [njs] Fixed AST printing with long strings values. In-Reply-To: References: Message-ID: An HTML attachment was scrubbed... URL: From alexander.borisov at nginx.com Fri Jun 5 12:26:49 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 05 Jun 2020 12:26:49 +0000 Subject: [njs] Parser: added line positions for AST nodes. Message-ID: details: https://hg.nginx.org/njs/rev/bc79f5c80452 branches: changeset: 1426:bc79f5c80452 user: Alexander Borisov date: Thu Jun 04 17:26:01 2020 +0300 description: Parser: added line positions for AST nodes. diffstat: src/njs_lexer.c | 4 +- src/njs_parser.c | 428 +++++++++++++++++++++++++++++++++++------------------- src/njs_parser.h | 2 + 3 files changed, 282 insertions(+), 152 deletions(-) diffs (truncated from 1381 to 1000 lines): diff -r 790bde011274 -r bc79f5c80452 src/njs_lexer.c --- a/src/njs_lexer.c Fri Jun 05 11:42:41 2020 +0000 +++ b/src/njs_lexer.c Thu Jun 04 17:26:01 2020 +0300 @@ -449,6 +449,7 @@ njs_lexer_make_token(njs_lexer_t *lexer, } token->type = njs_tokens[c]; + token->line = lexer->line; switch (token->type) { @@ -566,7 +567,6 @@ njs_lexer_make_token(njs_lexer_t *lexer, /* Fall through. */ default: - token->line = lexer->line; token->text.start = lexer->start - 1; token->text.length = lexer->start - token->text.start; @@ -668,7 +668,6 @@ njs_lexer_word(njs_lexer_t *lexer, njs_l 0x00, 0x00, 0x00, 0x00, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ }; - token->line = lexer->line; token->text.start = lexer->start - 1; hash_id = njs_djb_hash_add(NJS_DJB_HASH_INIT, *token->text.start); @@ -866,6 +865,7 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_ { u_char c; + token->line = lexer->line; token->text.start = lexer->start - 1; while (length != 0 && multi != NULL && lexer->start < lexer->end) { diff -r 790bde011274 -r bc79f5c80452 src/njs_parser.c --- a/src/njs_parser.c Fri Jun 05 11:42:41 2020 +0000 +++ b/src/njs_parser.c Thu Jun 04 17:26:01 2020 +0300 @@ -563,6 +563,7 @@ njs_parser(njs_parser_t *parser, njs_par } parser->node->token_type = NJS_TOKEN_END; + parser->node->token_line = parser->lexer->line; njs_parser_chain_top_set(parser, parser->node); @@ -921,6 +922,17 @@ njs_parser_expression_parenthesis(njs_pa } +static njs_int_t +njs_parser_set_line_state(njs_parser_t *parser, + njs_lexer_token_t *token, njs_queue_link_t *current) +{ + parser->node->token_line = (uint32_t) (uintptr_t) parser->target; + parser->target = NULL; + + return njs_parser_stack_pop(parser); +} + + /* * 12.2 Primary Expression. */ @@ -948,6 +960,7 @@ njs_parser_primary_expression_test(njs_p } node->u.value = njs_value_true; + node->token_line = token->line; parser->node = node; goto done; @@ -959,6 +972,7 @@ njs_parser_primary_expression_test(njs_p } node->u.value = njs_value_false; + node->token_line = token->line; parser->node = node; goto done; @@ -970,6 +984,7 @@ njs_parser_primary_expression_test(njs_p } njs_set_number(&node->u.value, token->number); + node->token_line = token->line; parser->node = node; goto done; @@ -980,6 +995,8 @@ njs_parser_primary_expression_test(njs_p return NJS_ERROR; } + node->token_line = token->line; + ret = njs_parser_string_create(parser->vm, token, &node->u.value); if (ret != NJS_OK) { return NJS_ERROR; @@ -996,6 +1013,8 @@ njs_parser_primary_expression_test(njs_p return NJS_ERROR; } + node->token_line = token->line; + ret = njs_parser_escape_string_create(parser, token, &node->u.value); if (ret != NJS_TOKEN_STRING) { return NJS_ERROR; @@ -1013,11 +1032,27 @@ njs_parser_primary_expression_test(njs_p /* ArrayLiteral */ case NJS_TOKEN_OPEN_BRACKET: + node = njs_parser_node_new(parser, NJS_TOKEN_ARRAY); + if (node == NULL) { + return NJS_ERROR; + } + + node->token_line = token->line; + parser->node = node; + njs_parser_next(parser, njs_parser_array_literal); break; /* ObjectLiteral */ case NJS_TOKEN_OPEN_BRACE: + node = njs_parser_node_new(parser, NJS_TOKEN_OBJECT); + if (node == NULL) { + return NJS_ERROR; + } + + node->token_line = token->line; + parser->node = node; + njs_parser_next(parser, njs_parser_object_literal); break; @@ -1039,7 +1074,6 @@ njs_parser_primary_expression_test(njs_p } node->token_line = token->line; - parser->node = node; njs_parser_next(parser, njs_parser_function_expression); @@ -1086,6 +1120,7 @@ njs_parser_primary_expression_test(njs_p return NJS_ERROR; } + node->token_line = token->line; parser->node = node; ret = njs_parser_regexp_literal(parser, token, current); @@ -1102,6 +1137,7 @@ njs_parser_primary_expression_test(njs_p return NJS_ERROR; } + node->token_line = token->line; parser->node = node; njs_parser_next(parser, njs_parser_template_literal); @@ -1140,6 +1176,7 @@ reference: return NJS_ERROR; } + node->token_line = token->line; parser->node = node; done: @@ -1259,6 +1296,8 @@ njs_parser_template_literal(njs_parser_t return NJS_ERROR; } + array->token_line = token->line; + template = parser->node; index = NJS_SCOPE_CALLEE_ARGUMENTS; @@ -1532,14 +1571,8 @@ static njs_int_t njs_parser_array_literal(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *array; - - array = njs_parser_node_new(parser, NJS_TOKEN_ARRAY); - if (array == NULL) { - return NJS_ERROR; - } - - parser->target = array; + parser->target = parser->node; + parser->node = NULL; njs_parser_next(parser, njs_parser_array_element_list); @@ -1644,20 +1677,16 @@ static njs_int_t njs_parser_object_literal(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *object, *node; - - object = njs_parser_node_new(parser, NJS_TOKEN_OBJECT); - if (object == NULL) { - return NJS_ERROR; - } + njs_parser_node_t *node; node = njs_parser_node_new(parser, 0); if (node == NULL) { return NJS_ERROR; } - node->left = object; - + node->left = parser->node; + + parser->node = NULL; parser->target = node; njs_parser_next(parser, njs_parser_property_definition_list); @@ -1750,6 +1779,10 @@ njs_parser_property_name_node(njs_parser property = njs_parser_node_string(parser->vm, token, parser); } + if (property != NULL) { + property->token_line = token->line; + } + return property; } @@ -2103,8 +2136,6 @@ njs_parser_property(njs_parser_t *parser switch (token->type) { case NJS_TOKEN_OPEN_BRACKET: - njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_node_new(parser, NJS_TOKEN_PROPERTY); if (node == NULL) { return NJS_ERROR; @@ -2112,9 +2143,12 @@ njs_parser_property(njs_parser_t *parser node->u.operation = NJS_VMCODE_PROPERTY_GET; node->left = parser->node; + node->token_line = token->line; parser->node = NULL; + njs_lexer_consume_token(parser->lexer, 1); + njs_parser_next(parser, njs_parser_expression); return njs_parser_after(parser, current, node, 1, @@ -2133,12 +2167,15 @@ njs_parser_property(njs_parser_t *parser } node->u.operation = NJS_VMCODE_PROPERTY_GET; + node->token_line = token->line; prop_node = njs_parser_node_string(parser->vm, token, parser); if (prop_node == NULL) { return NJS_ERROR; } + prop_node->token_line = token->line; + node->left = parser->node; node->right = prop_node; @@ -2153,15 +2190,17 @@ njs_parser_property(njs_parser_t *parser return NJS_DECLINED; case NJS_TOKEN_GRAVE: - njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_create_call(parser, parser->node, 0); if (node == NULL) { return NJS_ERROR; } + node->token_line = token->line; + parser->node = node; + njs_lexer_consume_token(parser->lexer, 1); + njs_parser_next(parser, njs_parser_template_literal); break; @@ -2437,18 +2476,20 @@ njs_parser_member_expression_new_after(n return NJS_ERROR; } + parser->node->token_line = token->line; + return njs_parser_stack_pop(parser); } - njs_lexer_consume_token(parser->lexer, 1); - func = njs_parser_create_call(parser, parser->node, 1); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_arguments); return njs_parser_after(parser, current, func, 1, @@ -2562,15 +2603,15 @@ njs_parser_call_expression_args(njs_pars return njs_parser_failed(parser); } - njs_lexer_consume_token(parser->lexer, 1); - func = njs_parser_create_call(parser, parser->node, 0); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_arguments); return njs_parser_after(parser, current, func, 1, @@ -2594,15 +2635,15 @@ njs_parser_call_expression_after(njs_par switch (token->type) { case NJS_TOKEN_OPEN_PARENTHESIS: - njs_lexer_consume_token(parser->lexer, 1); - func = njs_parser_create_call(parser, parser->node, 0); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_arguments); ret = njs_parser_after(parser, current, func, 1, @@ -2730,9 +2771,10 @@ njs_parser_argument_list_after(njs_parse node->index = parser->target->index + sizeof(njs_value_t); } + node->token_line = token->line; node->left = parser->node; + parser->node->dest = node; - parser->target->right = node; parser->node = node; @@ -2819,15 +2861,15 @@ njs_parser_optional_chain(njs_parser_t * switch (token->type) { case NJS_TOKEN_OPEN_PARENTHESIS: - njs_lexer_consume_token(parser->lexer, 2); - func = njs_parser_create_call(parser, parser->node, 0); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 2); njs_parser_next(parser, njs_parser_arguments); ret = njs_parser_after(parser, current, func, 1, @@ -2878,15 +2920,15 @@ njs_parser_optional_chain_after(njs_pars switch (token->type) { case NJS_TOKEN_OPEN_PARENTHESIS: - njs_lexer_consume_token(parser->lexer, 1); - func = njs_parser_create_call(parser, parser->node, 0); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_arguments); ret = njs_parser_after(parser, current, func, 1, @@ -2957,6 +2999,7 @@ njs_parser_new_expression_after(njs_pars return NJS_ERROR; } + func->token_line = token->line; parser->node = func; return njs_parser_stack_pop(parser); @@ -3028,15 +3071,15 @@ njs_parser_left_hand_side_expression_aft switch (token->type) { /* CallExpression */ case NJS_TOKEN_OPEN_PARENTHESIS: - njs_lexer_consume_token(parser->lexer, 1); - func = njs_parser_create_call(parser, parser->node, 0); if (func == NULL) { return NJS_ERROR; } + func->token_line = token->line; parser->node = func; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_arguments); ret = njs_parser_after(parser, current, func, 1, @@ -3108,17 +3151,18 @@ njs_parser_expression_node(njs_parser_t return njs_parser_stack_pop(parser); } - njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_node_new(parser, type); if (node == NULL) { return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; + njs_lexer_consume_token(parser->lexer, 1); + return njs_parser_after(parser, current, node, 0, after); } @@ -3154,6 +3198,7 @@ njs_parser_update_expression(njs_parser_ return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; njs_lexer_consume_token(parser->lexer, 1); @@ -3193,9 +3238,9 @@ njs_parser_update_expression_post(njs_pa return njs_parser_stack_pop(parser); } - njs_lexer_consume_token(parser->lexer, 1); - if (!njs_parser_is_lvalue(parser->node)) { + njs_lexer_consume_token(parser->lexer, 1); + njs_parser_ref_error(parser, "Invalid left-hand side in postfix operation"); return NJS_DONE; @@ -3206,10 +3251,14 @@ njs_parser_update_expression_post(njs_pa return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; + parser->node = node; + njs_lexer_consume_token(parser->lexer, 1); + return njs_parser_stack_pop(parser); } @@ -3293,17 +3342,18 @@ njs_parser_unary_expression(njs_parser_t njs_parser_unary_expression_after); } - njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_node_new(parser, type); if (node == NULL) { return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; parser->target = node; + njs_lexer_consume_token(parser->lexer, 1); + return njs_parser_after(parser, current, node, 0, njs_parser_unary_expression_next); } @@ -3435,6 +3485,7 @@ njs_parser_exponentiation_expression_mat return NJS_ERROR; } + node->token_line = token->line; node->u.operation = NJS_VMCODE_EXPONENTIATION; node->left = parser->node; node->left->dest = node; @@ -3501,6 +3552,7 @@ njs_parser_multiplicative_expression_mat return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; @@ -3563,6 +3615,7 @@ njs_parser_additive_expression_match(njs return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; @@ -3629,6 +3682,7 @@ njs_parser_shift_expression_match(njs_pa return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; @@ -3707,6 +3761,7 @@ njs_parser_relational_expression_match(n return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; @@ -3777,6 +3832,7 @@ njs_parser_equality_expression_match(njs return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; node->left->dest = node; @@ -3947,17 +4003,17 @@ njs_parser_coalesce_expression(njs_parse return njs_parser_failed(parser); } - njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_node_new(parser, NJS_TOKEN_COALESCE); if (node == NULL) { return NJS_ERROR; } + node->token_line = token->line; node->u.operation = NJS_VMCODE_COALESCE; node->left = parser->node; node->left->dest = node; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_bitwise_OR_expression); return njs_parser_after(parser, current, node, 0, @@ -4000,13 +4056,12 @@ njs_parser_conditional_question_mark(njs return njs_parser_stack_pop(parser); } - njs_lexer_consume_token(parser->lexer, 1); - cond = njs_parser_node_new(parser, NJS_TOKEN_CONDITIONAL); if (cond == NULL) { return NJS_ERROR; } + cond->token_line = token->line; cond->left = parser->node; node = njs_parser_node_new(parser, NJS_TOKEN_BRANCHING); @@ -4014,8 +4069,10 @@ njs_parser_conditional_question_mark(njs return NJS_ERROR; } + node->token_line = token->line; cond->right = node; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_assignment_expression); return njs_parser_after(parser, current, cond, 1, @@ -4277,6 +4334,7 @@ njs_parser_assignment_operator(njs_parse return NJS_ERROR; } + node->token_line = token->line; node->u.operation = operation; node->left = parser->node; @@ -4358,16 +4416,18 @@ njs_parser_statement(njs_parser_t *parse return njs_parser_stack_pop(parser); case NJS_TOKEN_EXPORT: + parser->line = token->line; + njs_lexer_consume_token(parser->lexer, 1); - njs_parser_next(parser, njs_parser_export); return njs_parser_after(parser, current, parser->node, 1, njs_parser_statement_after); case NJS_TOKEN_IMPORT: + parser->line = token->line; + njs_lexer_consume_token(parser->lexer, 1); - njs_parser_next(parser, njs_parser_import); return njs_parser_after(parser, current, parser->node, 1, @@ -4425,12 +4485,10 @@ njs_parser_statement_wo_node(njs_parser_ break; case NJS_TOKEN_CONTINUE: - parser->line = token->line; njs_parser_next(parser, njs_parser_continue_statement); break; case NJS_TOKEN_BREAK: - parser->line = token->line; njs_parser_next(parser, njs_parser_break_statement); break; @@ -4474,6 +4532,8 @@ njs_parser_statement_wo_node(njs_parser_ return NJS_OK; } + parser->line = token->line; + njs_lexer_consume_token(parser->lexer, 1); return NJS_OK; @@ -4577,6 +4637,7 @@ static njs_int_t njs_parser_block_statement(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { + void *target; njs_int_t ret; ret = njs_parser_scope_begin(parser, NJS_SCOPE_BLOCK); @@ -4584,16 +4645,19 @@ njs_parser_block_statement(njs_parser_t return NJS_ERROR; } + target = (void *) (uintptr_t) parser->line; parser->node = NULL; if (token->type == NJS_TOKEN_CLOSE_BRACE) { + parser->target = target; + njs_parser_next(parser, njs_parser_block_statement_close_brace); return NJS_OK; } njs_parser_next(parser, njs_parser_statement_list); - return njs_parser_after(parser, current, NULL, 1, + return njs_parser_after(parser, current, target, 1, njs_parser_block_statement_close_brace); } @@ -4606,6 +4670,8 @@ njs_parser_block_statement_open_brace(nj return njs_parser_failed(parser); } + parser->line = token->line; + njs_lexer_consume_token(parser->lexer, 1); token = njs_lexer_token(parser->lexer, 0); @@ -4632,8 +4698,11 @@ njs_parser_block_statement_close_brace(n return NJS_ERROR; } + node->token_line = (uint32_t) (uintptr_t) parser->target; node->left = parser->node; node->right = NULL; + + parser->target = NULL; parser->node = node; njs_parser_scope_end(parser); @@ -4766,6 +4835,8 @@ njs_parser_variable_declaration(njs_pars return NJS_ERROR; } + name->token_line = token->line; + parser->node = name; njs_lexer_consume_token(parser->lexer, 1); @@ -4776,11 +4847,16 @@ njs_parser_variable_declaration(njs_pars } ret = njs_parser_initializer_assign(parser, NJS_TOKEN_VAR); + if (ret != NJS_OK) { + return ret; + } + + parser->node->token_line = token->line; if (token->type == NJS_TOKEN_ASSIGNMENT) { njs_parser_next(parser, njs_parser_initializer); - return ret; + return NJS_OK; } parser->target = parser->node; @@ -4788,7 +4864,7 @@ njs_parser_variable_declaration(njs_pars njs_parser_next(parser, njs_parser_initializer_after); - return ret; + return NJS_OK; } @@ -4923,6 +4999,8 @@ njs_parser_if_statement(njs_parser_t *pa return NJS_ERROR; } + node->token_line = parser->line; + parser->node = NULL; njs_parser_next(parser, njs_parser_expression); @@ -4965,12 +5043,23 @@ static njs_int_t njs_parser_else_statement(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { + njs_parser_node_t *node; + parser->target->right = parser->node; parser->node = NULL; if (token->type == NJS_TOKEN_ELSE) { + node = njs_parser_node_new(parser, NJS_TOKEN_BRANCHING); + if (node == NULL) { + return NJS_ERROR; + } + + node->token_line = token->line; + node->left = parser->target->right; + + parser->target->right = node; + njs_lexer_consume_token(parser->lexer, 1); - njs_parser_next(parser, njs_parser_statement_wo_node); return njs_parser_after(parser, current, parser->target, 1, @@ -4987,17 +5076,7 @@ static njs_int_t njs_parser_else_statement_after(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *node; - - node = njs_parser_node_new(parser, NJS_TOKEN_BRANCHING); - if (node == NULL) { - return NJS_ERROR; - } - - node->left = parser->target->right; - node->right = parser->node; - - parser->target->right = node; + parser->target->right->right = parser->node; parser->node = parser->target; @@ -5009,11 +5088,20 @@ static njs_int_t njs_parser_iteration_statement_do(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { + njs_parser_node_t *node; + + node = njs_parser_node_new(parser, NJS_TOKEN_DO); + if (node == NULL) { + return NJS_ERROR; + } + + node->token_line = parser->line; + parser->node = NULL; njs_parser_next(parser, njs_parser_statement_wo_node); - return njs_parser_after(parser, current, NULL, 1, + return njs_parser_after(parser, current, node, 1, njs_parser_iteration_statement_do_while); } @@ -5026,11 +5114,13 @@ njs_parser_iteration_statement_do_while( return njs_parser_failed(parser); } + parser->target->left = parser->node; + njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_expression_parenthesis); - return njs_parser_after(parser, current, parser->node, 1, + return njs_parser_after(parser, current, parser->target, 1, njs_parser_do_while_semicolon); } @@ -5039,20 +5129,12 @@ static njs_int_t njs_parser_do_while_semicolon(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *node; - if (parser->strict_semicolon) { return njs_parser_failed(parser); } - node = njs_parser_node_new(parser, NJS_TOKEN_DO); - if (node == NULL) { - return NJS_ERROR; - } - - node->left = parser->target; - node->right = parser->node; - parser->node = node; + parser->target->right = parser->node; + parser->node = parser->target; return njs_parser_stack_pop(parser); } @@ -5062,9 +5144,18 @@ static njs_int_t njs_parser_iteration_statement_while(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { + njs_parser_node_t *node; + + node = njs_parser_node_new(parser, NJS_TOKEN_WHILE); + if (node == NULL) { + return NJS_ERROR; + } + + node->token_line = token->line; + njs_parser_next(parser, njs_parser_expression_parenthesis); - return njs_parser_after(parser, current, NULL, 1, + return njs_parser_after(parser, current, node, 1, njs_parser_while_statement); } @@ -5073,15 +5164,13 @@ static njs_int_t njs_parser_while_statement(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *node; - - node = parser->node; - + parser->target->right = parser->node; parser->node = NULL; njs_parser_next(parser, njs_parser_statement_wo_node); - return njs_parser_after(parser, current, node, 1, njs_parser_while_after); + return njs_parser_after(parser, current, parser->target, 1, + njs_parser_while_after); } @@ -5089,16 +5178,8 @@ static njs_int_t njs_parser_while_after(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *node; - - node = njs_parser_node_new(parser, NJS_TOKEN_WHILE); - if (node == NULL) { - return NJS_ERROR; - } - - node->left = parser->node; - node->right = parser->target; - parser->node = node; + parser->target->left = parser->node; + parser->node = parser->target; return njs_parser_stack_pop(parser); } @@ -5113,7 +5194,9 @@ njs_parser_iteration_statement_for(njs_p njs_parser_next(parser, njs_parser_iteration_statement_for_map); - return NJS_OK; + return njs_parser_after(parser, current, + (void *) (uintptr_t) parser->line, 1, + njs_parser_set_line_state); } if (token->type == NJS_TOKEN_AWAIT) { @@ -5226,7 +5309,7 @@ njs_parser_for_var_binding_or_var_list(n { njs_int_t ret; njs_lexer_token_t *next; - njs_parser_node_t *node; + njs_parser_node_t *node, *var; switch (token->type) { /* BindingPattern */ @@ -5256,13 +5339,23 @@ njs_parser_for_var_binding_or_var_list(n return NJS_OK; } - node = njs_parser_variable_node(parser, token->unique_id, + var = njs_parser_variable_node(parser, token->unique_id, NJS_VARIABLE_VAR); + if (var == NULL) { + return NJS_ERROR; + } + + var->token_line = token->line; + + parser->node = NULL; + + node = njs_parser_node_new(parser, NJS_TOKEN_IN); if (node == NULL) { return NJS_ERROR; } - parser->node = NULL; + node->token_line = next->line; + node->left = var; njs_parser_next(parser, njs_parser_expression); @@ -5289,27 +5382,18 @@ static njs_int_t njs_parser_for_var_in_statement(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - njs_parser_node_t *node; - if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) { return njs_parser_failed(parser); } njs_lexer_consume_token(parser->lexer, 1); - node = njs_parser_node_new(parser, NJS_TOKEN_IN); - if (node == NULL) { - return NJS_ERROR; - } - - node->left = parser->target; - node->right = parser->node; - + parser->target->right = parser->node; parser->node = NULL; njs_parser_next(parser, njs_parser_statement_wo_node); - return njs_parser_after(parser, current, node, 1, + return njs_parser_after(parser, current, parser->target, 1, njs_parser_for_var_in_statement_after); } @@ -5658,6 +5742,8 @@ njs_parser_return_statement(njs_parser_t return NJS_ERROR; } + node->token_line = parser->line; + switch (token->type) { case NJS_TOKEN_SEMICOLON: break; @@ -5734,6 +5820,8 @@ njs_parser_switch_statement(njs_parser_t return NJS_ERROR; } + swtch->token_line = parser->line; + njs_parser_next(parser, njs_parser_expression_parenthesis); ret = njs_parser_after(parser, current, swtch, 1, @@ -5811,6 +5899,7 @@ njs_parser_switch_case_def(njs_parser_t return NJS_ERROR; } + branch->token_line = token->line; branch->right = node; njs_parser_next(parser, njs_parser_expression); From mdounin at mdounin.ru Fri Jun 5 13:22:05 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 5 Jun 2020 16:22:05 +0300 Subject: [PATCH] introduce new variable fs_watermark for proxy_cache_path In-Reply-To: References: Message-ID: <20200605132205.GF12747@mdounin.ru> Hello! On Thu, May 07, 2020 at 01:40:54AM +0200, Adam Bambuch wrote: > # HG changeset patch > # User Adam Bambuch > # Date 1588808163 -7200 > # Thu May 07 01:36:03 2020 +0200 > # Node ID 8d054b64f07457cad2b74376d5f88162c887ba35 > # Parent 716eddd74bc2831537f5b3f7ecd16ad3e516d043 > introduce new variable fs_watermark for proxy_cache_path > > This configuration parameter should help with better disk usage, > especially in environments, where nginx doesn't have a separate > partition for caching and disk space is shared between multiple apps. > It could also help in environments, where cache contains many small > files, and cache loader can't load all the files in a reasonable time > and therefore max_size is exceeded for many hours after nginx restart. [...] Thanks for the patch. This is something I was thinking about for a while, since such approach indeed can be better than existing cache clearing in many cases, even if the cache partition is dedicated to nginx: in particular, it can be used to keep disk usage under control regardless of the amount of temporary files kept on the same partition. The patch below simplifies the approach, and also fixes some issues with the patch. Notable changes include: - The parameter is renamed to "min_free", which is in line with "max_size" and seems to be much more readable. - Error reporting is removed and statfs() / statvfs() / GetDiskFreeSpaceEx() errors, if any, instead result in maximum amount of free space being reported (and min_free cache clearing effectively disabled), similarly to how it happens with ngx_fs_bsize(). - Fixed overflow on 32-bit platforms and incorrect cast in "return (ssize_t) (fs.f_bavail * fs.f_bsize);" in statfs() and statvfs() cases. - Fixed incorrect usage of fs.f_bsize instead of fs.f_frsize in statvfs() case. - Fixed configuration parsing to report "not available on this platform" if statfs() / statvfs() is not present for some reason. - Slightly improved ngx_http_file_cache_manager() logic to avoid reporting very large free space values in debug logs if min_free is not configured. - Unused output arguments of GetDiskFreeSpaceEx() replaced with NULL pointers, since GetDiskFreeSpaceEx() allows this. - Various style issues fixed. # HG changeset patch # User Maxim Dounin # Date 1591326790 -10800 # Fri Jun 05 06:13:10 2020 +0300 # Node ID 850c0efeaddaf3274f791c90d321d295702bd55c # Parent 14665e4b377c9eae1f07de003b6248923ca087ee Cache: introduced min_free cache clearing. Clearing cache based on free space left on a filesystem is expected to allow better disk utilization in some cases, notably when disk space might be also used for something other than nginx cache (including nginx own temporary files) and while loading cache (when cache size might be inaccurate for a while, effectively disabling max_size cache clearing). Based on a patch by Adam Bambuch. diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -160,6 +160,7 @@ struct ngx_http_file_cache_s { ngx_path_t *path; + off_t min_free; off_t max_size; size_t bsize; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1959,7 +1959,7 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; + off_t size, free; time_t wait; ngx_msec_t elapsed, next; ngx_uint_t count, watermark; @@ -1988,7 +1988,19 @@ ngx_http_file_cache_manager(void *data) size, count, (ngx_int_t) watermark); if (size < cache->max_size && count < watermark) { - break; + + if (!cache->min_free) { + break; + } + + free = ngx_fs_available(cache->path->name.data); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache free: %O", free); + + if (free > cache->min_free) { + break; + } } wait = ngx_http_file_cache_forced_expire(cache); @@ -2304,7 +2316,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t { char *confp = conf; - off_t max_size; + off_t max_size, min_free; u_char *last, *p; time_t inactive; ssize_t size; @@ -2341,6 +2353,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; + min_free = 0; value = cf->args->elts; @@ -2476,6 +2489,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t continue; } + if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) { + +#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS) + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + min_free = ngx_parse_offset(&s); + if (min_free < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid min_free value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "min_free is not supported " + "on this platform, ignored"); +#endif + + continue; + } + if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); @@ -2607,6 +2643,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t cache->inactive = inactive; cache->max_size = max_size; + cache->min_free = min_free; caches = (ngx_array_t *) (confp + cmd->offset); diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -884,6 +884,19 @@ ngx_fs_bsize(u_char *name) return (size_t) fs.f_bsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_bsize; +} + #elif (NGX_HAVE_STATVFS) size_t @@ -908,6 +921,19 @@ ngx_fs_bsize(u_char *name) return (size_t) fs.f_frsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_frsize; +} + #else size_t @@ -916,4 +942,11 @@ ngx_fs_bsize(u_char *name) return 512; } + +off_t +ngx_fs_available(u_char *name) +{ + return NGX_MAX_OFF_T_VALUE; +} + #endif diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -349,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); #if (NGX_HAVE_OPENAT) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -658,6 +658,19 @@ ngx_fs_bsize(u_char *name) } +off_t +ngx_fs_available(u_char *name) +{ + ULARGE_INTEGER navail; + + if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) navail.QuadPart; +} + + static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, size_t len) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -259,6 +259,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #define ngx_directio_off_n "ngx_directio_off_n" size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); #define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE) -- Maxim Dounin http://mdounin.ru/ From svetlightsm at mail.ru Fri Jun 5 15:08:49 2020 From: svetlightsm at mail.ru (svetlightsm at mail.ru) Date: Fri, 05 Jun 2020 18:08:49 +0300 Subject: [PATCH] introduce new variable fs_watermark for proxy_cache_path In-Reply-To: <20200605132205.GF12747@mdounin.ru> References: <20200605132205.GF12747@mdounin.ru> Message-ID: An HTML attachment was scrubbed... URL: From svetlightsm at mail.ru Fri Jun 5 15:08:49 2020 From: svetlightsm at mail.ru (svetlightsm at mail.ru) Date: Fri, 05 Jun 2020 18:08:49 +0300 Subject: [njs] Parser: added line positions for AST nodes. In-Reply-To: References: Message-ID: An HTML attachment was scrubbed... URL: From svetlightsm at mail.ru Fri Jun 5 15:08:49 2020 From: svetlightsm at mail.ru (svetlightsm at mail.ru) Date: Fri, 05 Jun 2020 18:08:49 +0300 Subject: [njs] Added %TypedArray%.prototype.sort(). In-Reply-To: References: Message-ID: <9M0M9A4ATAU4.OXIP5ZQUGFB6@DESKTOP-DRHES89> An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: IMG_1317.jpg Type: image/jpeg Size: 306903 bytes Desc: not available URL: From alexander.borisov at nginx.com Sat Jun 6 15:16:27 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Sat, 06 Jun 2020 15:16:27 +0000 Subject: [njs] Parser: correctly fixing closing brace unwinding for invalid syntax. Message-ID: details: https://hg.nginx.org/njs/rev/857c2166d10b branches: changeset: 1427:857c2166d10b user: Alexander Borisov date: Sat Jun 06 18:15:07 2020 +0300 description: Parser: correctly fixing closing brace unwinding for invalid syntax. The issue was introduced in 86f55a7dc4a4. Previous attempts to catch unprocessed token in ea1754b79e7a and 61dce54ce3d5 were misplaced. diffstat: src/njs_parser.c | 78 ++++++++++----------------------- src/test/njs_unit_test.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 53 deletions(-) diffs (367 lines): diff -r bc79f5c80452 -r 857c2166d10b src/njs_parser.c --- a/src/njs_parser.c Thu Jun 04 17:26:01 2020 +0300 +++ b/src/njs_parser.c Sat Jun 06 18:15:07 2020 +0300 @@ -1154,7 +1154,7 @@ njs_parser_primary_expression_test(njs_p njs_parser_next(parser, njs_parser_expression); - return njs_parser_after(parser, current, NULL, 1, + return njs_parser_after(parser, current, NULL, 0, njs_parser_close_parenthesis); default: @@ -3137,10 +3137,6 @@ njs_parser_expression_node(njs_parser_t { njs_parser_node_t *node; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3163,7 +3159,7 @@ njs_parser_expression_node(njs_parser_t njs_lexer_consume_token(parser->lexer, 1); - return njs_parser_after(parser, current, node, 0, after); + return njs_parser_after(parser, current, node, 1, after); } @@ -3204,7 +3200,7 @@ njs_parser_update_expression(njs_parser_ njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_left_hand_side_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_update_expression_unary); } @@ -3267,10 +3263,6 @@ static njs_int_t njs_parser_update_expression_unary(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (!njs_parser_is_lvalue(parser->node)) { njs_parser_ref_error(parser, "Invalid left-hand side in prefix operation"); @@ -3354,7 +3346,7 @@ njs_parser_unary_expression(njs_parser_t njs_lexer_consume_token(parser->lexer, 1); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_unary_expression_next); } @@ -3382,10 +3374,6 @@ njs_parser_unary_expression_next(njs_par njs_token_type_t type; njs_parser_node_t *node; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - type = parser->target->token_type; node = parser->node; @@ -3464,10 +3452,6 @@ njs_parser_exponentiation_expression_mat { njs_parser_node_t *node; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3494,7 +3478,7 @@ njs_parser_exponentiation_expression_mat njs_parser_next(parser, njs_parser_exponentiation_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_exponentiation_expression_match); } @@ -3520,10 +3504,6 @@ njs_parser_multiplicative_expression_mat njs_parser_node_t *node; njs_vmcode_operation_t operation; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3561,7 +3541,7 @@ njs_parser_multiplicative_expression_mat njs_parser_next(parser, njs_parser_exponentiation_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_multiplicative_expression_match); } @@ -3587,10 +3567,6 @@ njs_parser_additive_expression_match(njs njs_parser_node_t *node; njs_vmcode_operation_t operation; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3624,7 +3600,7 @@ njs_parser_additive_expression_match(njs njs_parser_next(parser, njs_parser_multiplicative_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_additive_expression_match); } @@ -3650,10 +3626,6 @@ njs_parser_shift_expression_match(njs_pa njs_parser_node_t *node; njs_vmcode_operation_t operation; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3691,7 +3663,7 @@ njs_parser_shift_expression_match(njs_pa njs_parser_next(parser, njs_parser_additive_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_shift_expression_match); } @@ -3717,10 +3689,6 @@ njs_parser_relational_expression_match(n njs_parser_node_t *node; njs_vmcode_operation_t operation; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3770,7 +3738,7 @@ njs_parser_relational_expression_match(n njs_parser_next(parser, njs_parser_shift_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_relational_expression_match); } @@ -3796,10 +3764,6 @@ njs_parser_equality_expression_match(njs njs_parser_node_t *node; njs_vmcode_operation_t operation; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - if (parser->target != NULL) { parser->target->right = parser->node; parser->target->right->dest = parser->target; @@ -3841,7 +3805,7 @@ njs_parser_equality_expression_match(njs njs_parser_next(parser, njs_parser_relational_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_equality_expression_match); } @@ -3979,10 +3943,6 @@ njs_parser_coalesce_expression(njs_parse njs_token_type_t type; njs_parser_node_t *node; - if (parser->ret != NJS_OK) { - return njs_parser_failed(parser); - } - node = parser->node; if (parser->target != NULL) { @@ -4016,7 +3976,7 @@ njs_parser_coalesce_expression(njs_parse njs_lexer_consume_token(parser->lexer, 1); njs_parser_next(parser, njs_parser_bitwise_OR_expression); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_coalesce_expression); } @@ -4657,7 +4617,7 @@ njs_parser_block_statement(njs_parser_t njs_parser_next(parser, njs_parser_statement_list); - return njs_parser_after(parser, current, target, 1, + return njs_parser_after(parser, current, target, 0, njs_parser_block_statement_close_brace); } @@ -4689,6 +4649,10 @@ njs_parser_block_statement_close_brace(n { njs_parser_node_t *node; + if (parser->ret != NJS_OK) { + return njs_parser_failed(parser); + } + if (token->type != NJS_TOKEN_CLOSE_BRACE) { return njs_parser_failed(parser); } @@ -4728,7 +4692,15 @@ njs_parser_statement_list_next(njs_parse njs_queue_link_t *current) { if (parser->ret != NJS_OK) { - parser->node = parser->target; + if (token->type != NJS_TOKEN_CLOSE_BRACE) { + parser->node = parser->target; + return njs_parser_stack_pop(parser); + } + + return njs_parser_failed(parser); + } + + if (token->type == NJS_TOKEN_CLOSE_BRACE) { return njs_parser_stack_pop(parser); } diff -r bc79f5c80452 -r 857c2166d10b src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Jun 04 17:26:01 2020 +0300 +++ b/src/test/njs_unit_test.c Sat Jun 06 18:15:07 2020 +0300 @@ -16861,6 +16861,114 @@ static njs_unit_test_t njs_test[] = { njs_str("{{}{1>>}"), njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{r=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}{var a = }"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}T=>}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b +}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b -}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b *}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b /}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b %}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a = b++}"), + njs_str("ReferenceError: \"a\" is not defined in 1") }, + + { njs_str("{{}a = b--}"), + njs_str("ReferenceError: \"a\" is not defined in 1") }, + + { njs_str("{{}a =}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a +=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a -=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a *=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a /=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a %=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a ===}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a ==}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a !=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a !==}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a >}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a <}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a <=}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a &&}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a ||}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a ??}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a &}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a |}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a ^}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a <<}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}a >>}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}new}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}delete}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}void}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{}typeof}"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("{{} ({a: 1, b: {}\n}\n})\n}"), + njs_str("SyntaxError: Unexpected token \"}\" in 3") }, }; From varuncvarada at gmail.com Sat Jun 6 21:08:40 2020 From: varuncvarada at gmail.com (Varun Varada) Date: Sat, 06 Jun 2020 16:08:40 -0500 Subject: [PATCH] HTTP: factor out server name into a constant Message-ID: # HG changeset patch # User Varun Varada # Date 1591475111 18000 # Sat Jun 06 15:25:11 2020 -0500 # Node ID f37aa29453e006bdc37cbe7d9f65eec0de27b731 # Parent 699f6e55bbb4672632e7def5c65b1dbae2960380 HTTP: factor out server name into a constant This commit factors out the name of the server ("nginx") into a constant to make the code DRY and so that modifying the server name, if necessary, can be done in one place. diff -r 699f6e55bbb4 -r f37aa29453e0 src/core/nginx.h --- a/src/core/nginx.h Wed Jun 03 19:11:32 2020 +0300 +++ b/src/core/nginx.h Sat Jun 06 15:25:11 2020 -0500 @@ -10,8 +10,9 @@ #define nginx_version 1019001 +#define NGINX_NAME "nginx" #define NGINX_VERSION "1.19.1" -#define NGINX_VER "nginx/" NGINX_VERSION +#define NGINX_VER NGINX_NAME "/" NGINX_VERSION #ifdef NGX_BUILD #define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")" diff -r 699f6e55bbb4 -r f37aa29453e0 src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c Wed Jun 03 19:11:32 2020 +0300 +++ b/src/http/ngx_http_header_filter_module.c Sat Jun 06 15:25:11 2020 -0500 @@ -46,7 +46,7 @@ }; -static u_char ngx_http_server_string[] = "Server: nginx" CRLF; +static u_char ngx_http_server_string[] = "Server: " NGINX_NAME CRLF; static u_char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF; static u_char ngx_http_server_build_string[] = "Server: " NGINX_VER_BUILD CRLF; diff -r 699f6e55bbb4 -r f37aa29453e0 src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c Wed Jun 03 19:11:32 2020 +0300 +++ b/src/http/v2/ngx_http_v2_filter_module.c Sat Jun 06 15:25:11 2020 -0500 @@ -148,12 +148,14 @@ ngx_http_core_srv_conf_t *cscf; u_char addr[NGX_SOCKADDR_STRLEN]; - static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7"; #if (NGX_HTTP_GZIP) static const u_char accept_encoding[12] = "\x8b\x84\x84\x2d\x69\x5b\x05\x44\x3c\x86\xaa\x6f"; #endif + static size_t nginx_len = ngx_http_v2_literal_size(NGINX_NAME); + static u_char nginx[ngx_http_v2_literal_size(NGINX_NAME)]; + static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER); static u_char nginx_ver[ngx_http_v2_literal_size(NGINX_VER)]; @@ -268,7 +270,7 @@ len += 1 + nginx_ver_build_len; } else { - len += 1 + sizeof(nginx); + len += 1 + nginx_len; } } @@ -476,8 +478,9 @@ NGINX_VER_BUILD); } else { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 output header: \"server: nginx\""); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 output header: \"server: %s\"", + NGINX_NAME); } *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); @@ -502,7 +505,14 @@ pos = ngx_cpymem(pos, nginx_ver_build, nginx_ver_build_len); } else { - pos = ngx_cpymem(pos, nginx, sizeof(nginx)); + if (nginx[0] == '\0') { + p = ngx_http_v2_write_value(nginx, + (u_char *) NGINX_NAME, + sizeof(NGINX_NAME) - 1, tmp); + nginx_len = p - nginx; + } + + pos = ngx_cpymem(pos, nginx, nginx_len); } } From mdounin at mdounin.ru Sat Jun 6 23:18:23 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 7 Jun 2020 02:18:23 +0300 Subject: [PATCH] HTTP: factor out server name into a constant In-Reply-To: References: Message-ID: <20200606231823.GH12747@mdounin.ru> Hello! On Sat, Jun 06, 2020 at 04:08:40PM -0500, Varun Varada wrote: > # HG changeset patch > # User Varun Varada > # Date 1591475111 18000 > # Sat Jun 06 15:25:11 2020 -0500 > # Node ID f37aa29453e006bdc37cbe7d9f65eec0de27b731 > # Parent 699f6e55bbb4672632e7def5c65b1dbae2960380 > HTTP: factor out server name into a constant > > This commit factors out the name of the server ("nginx") into a > constant to make the code DRY and so that modifying the server > name, if necessary, can be done in one place. Thank you for the patch, but no. While this change may help people "modifying the server name", such a change would have a negative impact on nginx itself. Consider looking at this ticket instead: https://trac.nginx.org/nginx/ticket/1644 -- Maxim Dounin http://mdounin.ru/ From varuncvarada at gmail.com Sun Jun 7 01:01:57 2020 From: varuncvarada at gmail.com (Varun Varada) Date: Sat, 6 Jun 2020 20:01:57 -0500 Subject: [PATCH] HTTP: factor out server name into a constant In-Reply-To: <20200606231823.GH12747@mdounin.ru> References: <20200606231823.GH12747@mdounin.ru> Message-ID: On Sat, 6 Jun 2020 at 18:18, Maxim Dounin wrote: > > Hello! > > On Sat, Jun 06, 2020 at 04:08:40PM -0500, Varun Varada wrote: > > > # HG changeset patch > > # User Varun Varada > > # Date 1591475111 18000 > > # Sat Jun 06 15:25:11 2020 -0500 > > # Node ID f37aa29453e006bdc37cbe7d9f65eec0de27b731 > > # Parent 699f6e55bbb4672632e7def5c65b1dbae2960380 > > HTTP: factor out server name into a constant > > > > This commit factors out the name of the server ("nginx") into a > > constant to make the code DRY and so that modifying the server > > name, if necessary, can be done in one place. > > Thank you for the patch, but no. While this change may help > people "modifying the server name", such a change would have a > negative impact on nginx itself. Modifying the server name is a secondary concern. Currently, the name of the server is hard-coded in multiple places which is not a best practice. > > Consider looking at this ticket instead: > > https://trac.nginx.org/nginx/ticket/1644 That seems to have to do with a behavioural issue, which is unrelated to making the code DRY. Varun From mdounin at mdounin.ru Sun Jun 7 02:17:21 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 7 Jun 2020 05:17:21 +0300 Subject: [PATCH] HTTP: factor out server name into a constant In-Reply-To: References: <20200606231823.GH12747@mdounin.ru> Message-ID: <20200607021721.GI12747@mdounin.ru> Hello! On Sat, Jun 06, 2020 at 08:01:57PM -0500, Varun Varada wrote: > On Sat, 6 Jun 2020 at 18:18, Maxim Dounin wrote: > > > > On Sat, Jun 06, 2020 at 04:08:40PM -0500, Varun Varada wrote: > > > > > # HG changeset patch > > > # User Varun Varada > > > # Date 1591475111 18000 > > > # Sat Jun 06 15:25:11 2020 -0500 > > > # Node ID f37aa29453e006bdc37cbe7d9f65eec0de27b731 > > > # Parent 699f6e55bbb4672632e7def5c65b1dbae2960380 > > > HTTP: factor out server name into a constant > > > > > > This commit factors out the name of the server ("nginx") into a > > > constant to make the code DRY and so that modifying the server > > > name, if necessary, can be done in one place. > > > > Thank you for the patch, but no. While this change may help > > people "modifying the server name", such a change would have a > > negative impact on nginx itself. > > Modifying the server name is a secondary concern. Currently, the name > of the server is hard-coded in multiple places which is not a best > practice. Thank you for your opinion. In your patch, the name of the server, nginx, is hardcoded in eleven additional places compared to the original code. So, with your patch we'll have eleven additional places to change if we'll ever decide to rename nginx to something else. The fact that the string to be returned to HTTP clients can be changed in a single place is irrelevant as it is not expected to be changed separately from changing the name of the server. Not to mention the patch breaks pre-encoding of the name with HPACK in HTTP/2, and hence implies run-time costs. Overall, this looks like clearly negative change. And this is what was written above in the short form: "negative impact on nginx itself". > > Consider looking at this ticket instead: > > > > https://trac.nginx.org/nginx/ticket/1644 > > That seems to have to do with a behavioural issue, which is unrelated > to making the code DRY. Sure, this is a behavioural issue. And also this is the only understandable reason for the patch you've suggested, since the change in question clearly makes the code worse. If you indeed think that the patch "makes the code DRY", and therefore it is a good thing to do - you may want to reconsider how to apply the DRY principle, you are doing it wrong (hint: in many cases duplicating things is beneficial). If you are instead lying to yourself trying to pretend that "modifying the server name is a secondary concern", and want instead make it easier to modify the string returned to HTTP clients, then please refer to the ticket linked above. We are not going to accept patches making such modifications easier. Instead of trying to submit such patches, consider making it clear - for yourself in the first place - that such modifications should not be done. -- Maxim Dounin http://mdounin.ru/ From jmheisz at gmail.com Sun Jun 7 03:43:40 2020 From: jmheisz at gmail.com (Jeff Heisz) Date: Sat, 6 Jun 2020 23:43:40 -0400 Subject: General Development Inquiry Message-ID: Giving this one more try with a few questions this time. 1) This mailing list used to be more discussion oriented but seems to be mainly patch notifications now. Is there a more appropriate channel to ask these kind of module development questions for NGINX? 2) I'm actually working on a second module/system aside from the one mentioned in my previous post. This might actually be an easier question? It's using a custom upstream (like the memcache one) to talk a binary protocol to another daemon with requests/responses. For the most part it works, but there is one oddity that I can't seem to resolve - the daemon can respond with an HTML code/header set and then a response body. My upstream process_header function is setting up all of the respective HTTP headers (content length, etc.) and buffer positioning to stream the response and NGINX is issuing it to the browser. However, it doesn't finalize the request, instead waits for more data (which isn't coming, the response is complete) from the daemon and then times out after a minute and closes the connection. My suspicion is that the 'built-in' upstream handing is designed around servers that close the connection after the response is issued. But my daemon doesn't need to do that, so I'm trying to essentially use upstream with keepalive. Do I also need to provide an output filter to track the response length myself and properly mark the last buffer/end of chain so that the request finalizes without closing the upstream connection? Or is there some variable that I'm missing? Any suggested examples to look at? 3) Still looking for some sort of suggestion/ideas regarding my email from a few weeks ago (properly streaming large buffer responses from worker threads). I was excited when I noticed the njs elements for executing JS as part of a request, figuring that it would give some direction since you wouldn't want JS executing in the primary event thread. But from what I could tell, that appears to be exactly what it's doing :( I'm still thinking of some kind of extended worker pool model using IPC pipes to communicate from the threads to the main event loop (essentially a local upstream) but was just looking for thoughts/comments on best approach. Thanks in advance, jmh From eran.kornblau at kaltura.com Sun Jun 7 06:11:24 2020 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Sun, 7 Jun 2020 06:11:24 +0000 Subject: General Development Inquiry In-Reply-To: References: Message-ID: > 2) I'm actually working on a second module/system aside from the one mentioned in my previous post. This might actually be an easier question? It's using a custom upstream (like the memcache one) to talk a binary protocol to another daemon with requests/responses. For the most part it works, but there is one oddity that I can't seem to resolve - the daemon can respond with an HTML code/header set and then a response body. My upstream process_header function is setting up all of the respective HTTP headers (content length, etc.) and buffer positioning to stream the response and NGINX is issuing it to the browser. However, it doesn't finalize the request, instead waits for more data (which isn't coming, the response is complete) from the daemon and then times out after a minute and closes the connection. > My suspicion is that the 'built-in' upstream handing is designed around servers that close the connection after the response is issued. > But my daemon doesn't need to do that, so I'm trying to essentially use upstream with keepalive. Do I also need to provide an output filter to track the response length myself and properly mark the last buffer/end of chain so that the request finalizes without closing the upstream connection? Or is there some variable that I'm missing? Any suggested examples to look at? > >From your description, I'm guessing you didn't set r->upstream->length, you need to set it to the response size you're expecting. The upstream input_filter decrements u->length by the number of bytes read each time, when it reaches zero, the request is finalized. Eran From jmheisz at gmail.com Mon Jun 8 00:02:40 2020 From: jmheisz at gmail.com (Jeff Heisz) Date: Sun, 7 Jun 2020 20:02:40 -0400 Subject: General Development Inquiry In-Reply-To: References: Message-ID: Hmmm, hopefully this works because I subscribed with digest. Thank you very much for the feedback, I now had an idea of where to focus (I had a rough idea but this made it clearer). And now I know what the issue is but have no idea how to resolve it. My module was setting the upstream length as you suggested, hence my confusion. So I flooded the ngx_http_upstream code with debug statements to hunt down why the code around line 3614 (which calls finalize on the upstream length reaching zero) wasn't working. Turns out, the value was -1, which, if I read the code correctly, indicates that upstream is complete when connection is closed (consistent with what I was seeing). More debugging, turns out that my custom process_header method is setting the correct length to process, but immediately after that can the nginx server internally calls process_headers, which transfers all of the values between the upstream and request headers and...then...sets the upstream length to -1! Gah! So now I know what's wrong, but have no idea how to address it! There's no indicators or flags that I can see in the process_headers method to have it not reset the length to EOF! jmh > > Message: 2 > Date: Sun, 7 Jun 2020 06:11:24 +0000 > From: Eran Kornblau > To: "nginx-devel at nginx.org" > Subject: RE: General Development Inquiry > Message-ID: > > > Content-Type: text/plain; charset="us-ascii" > > > 2) I'm actually working on a second module/system aside from the one mentioned in my previous post. This might actually be an easier question? It's using a custom upstream (like the memcache one) to talk a binary protocol to another daemon with requests/responses. For the most part it works, but there is one oddity that I can't seem to resolve - the daemon can respond with an HTML code/header set and then a response body. My upstream process_header function is setting up all of the respective HTTP headers (content length, etc.) and buffer positioning to stream the response and NGINX is issuing it to the browser. However, it doesn't finalize the request, instead waits for more data (which isn't coming, the response is complete) from the daemon and then times out after a minute and closes the connection. > > My suspicion is that the 'built-in' upstream handing is designed around servers that close the connection after the response is issued. > > But my daemon doesn't need to do that, so I'm trying to essentially use upstream with keepalive. Do I also need to provide an output filter to track the response length myself and properly mark the last buffer/end of chain so that the request finalizes without closing the upstream connection? Or is there some variable that I'm missing? Any suggested examples to look at? > > > >From your description, I'm guessing you didn't set r->upstream->length, you need to set it to the response size you're expecting. The upstream input_filter decrements u->length by the number of bytes read each time, when it reaches zero, the request is finalized. > > Eran > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > ------------------------------ > > End of nginx-devel Digest, Vol 128, Issue 8 > ******************************************* From eran.kornblau at kaltura.com Mon Jun 8 05:06:10 2020 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Mon, 8 Jun 2020 05:06:10 +0000 Subject: General Development Inquiry In-Reply-To: References: Message-ID: > Hmmm, hopefully this works because I subscribed with digest. Thank you very much for the feedback, I now had an idea of where to focus (I had a rough idea but this made it clearer). And now I know what the issue is but have no idea how to resolve it. > > My module was setting the upstream length as you suggested, hence my confusion. So I flooded the ngx_http_upstream code with debug statements to hunt down why the code around line 3614 (which calls finalize on the upstream length reaching zero) wasn't working. Turns out, the value was -1, which, if I read the code correctly, indicates that upstream is complete when connection is closed (consistent with what I was seeing). > > More debugging, turns out that my custom process_header method is setting the correct length to process, but immediately after that can the nginx server internally calls process_headers, which transfers all of the values between the upstream and request headers and...then...sets the upstream length to -1! > > Gah! So now I know what's wrong, but have no idea how to address it! > There's no indicators or flags that I can see in the process_headers method to have it not reset the length to EOF! > > jmh > I think you should set it in the input_filter_init function, instead of process_header, this is what the proxy & memcached modules do... This function is called after process_header, so it won't get reset. Eran From jmheisz at gmail.com Mon Jun 8 15:27:32 2020 From: jmheisz at gmail.com (Jeff Heisz) Date: Mon, 8 Jun 2020 11:27:32 -0400 Subject: General Development Inquiry In-Reply-To: References: Message-ID: Ok, that did it, was a bit more painful than expected since I had to actually write a filter function (if you don't provide it, your init method is also overwritten by the default) but in the end it is now cleanly processing without hanging up on my upstream daemon. A suggested change to consider for the nginx core - perhaps at the end of the ngx_http_upstream_process_headers() function, instead of just blindly setting the length to -1, perhaps only do so if the upstream->keepalive is 0/false, so that a custom process_header can set an explicit length and the keepalive marker and not need to define a filter if the content is pass-through. Just a thought. Thanks again regardless. jmh > > > > My module was setting the upstream length as you suggested, hence my confusion. So I flooded the ngx_http_upstream code with debug statements to hunt down why the code around line 3614 (which calls finalize on the upstream length reaching zero) wasn't working. Turns out, the value was -1, which, if I read the code correctly, indicates that upstream is complete when connection is closed (consistent with what I was seeing). > > > > More debugging, turns out that my custom process_header method is setting the correct length to process, but immediately after that can the nginx server internally calls process_headers, which transfers all of the values between the upstream and request headers and...then...sets the upstream length to -1! > > > > Gah! So now I know what's wrong, but have no idea how to address it! > > There's no indicators or flags that I can see in the process_headers method to have it not reset the length to EOF! > > > > jmh > > > I think you should set it in the input_filter_init function, instead of process_header, this is what the proxy & memcached modules do... This function is called after process_header, so it won't get reset. > > Eran > From xeioex at nginx.com Tue Jun 9 16:48:19 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 09 Jun 2020 16:48:19 +0000 Subject: [njs] Introduced njs_array_push(). Message-ID: details: https://hg.nginx.org/njs/rev/724dedc6be18 branches: changeset: 1428:724dedc6be18 user: Dmitry Volyntsev date: Tue Jun 09 12:56:56 2020 +0000 description: Introduced njs_array_push(). diffstat: src/njs_array.h | 14 ++++++++++++++ src/njs_vm.c | 12 +----------- 2 files changed, 15 insertions(+), 11 deletions(-) diffs (51 lines): diff -r 857c2166d10b -r 724dedc6be18 src/njs_array.h --- a/src/njs_array.h Sat Jun 06 18:15:07 2020 +0300 +++ b/src/njs_array.h Tue Jun 09 12:56:56 2020 +0000 @@ -35,6 +35,20 @@ njs_int_t njs_array_prototype_to_string( njs_uint_t nargs, njs_index_t unused); +njs_inline njs_value_t * +njs_array_push(njs_vm_t *vm, njs_array_t *array) +{ + njs_int_t ret; + + ret = njs_array_expand(vm, array, 0, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + return &array->start[array->length++]; +} + + extern const njs_object_init_t njs_array_instance_init; extern const njs_object_type_init_t njs_array_type_init; diff -r 857c2166d10b -r 724dedc6be18 src/njs_vm.c --- a/src/njs_vm.c Sat Jun 06 18:15:07 2020 +0300 +++ b/src/njs_vm.c Tue Jun 09 12:56:56 2020 +0000 @@ -934,22 +934,12 @@ njs_vm_array_alloc(njs_vm_t *vm, njs_val njs_value_t * njs_vm_array_push(njs_vm_t *vm, njs_value_t *value) { - njs_int_t ret; - njs_array_t *array; - if (njs_slow_path(!njs_is_array(value))) { njs_type_error(vm, "njs_vm_array_push() argument is not array"); return NULL; } - array = njs_array(value); - - ret = njs_array_expand(vm, array, 0, 1); - if (njs_slow_path(ret != NJS_OK)) { - return NULL; - } - - return &array->start[array->length++]; + return njs_array_push(vm, njs_array(value)); } From xeioex at nginx.com Tue Jun 9 16:48:21 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 09 Jun 2020 16:48:21 +0000 Subject: [njs] Added fs.Dirent, fs.readdir() and friends. Message-ID: details: https://hg.nginx.org/njs/rev/b33402f10e82 branches: changeset: 1429:b33402f10e82 user: Artem S. Povalyukhin date: Sun May 31 08:45:41 2020 +0300 description: Added fs.Dirent, fs.readdir() and friends. This closes #254 issue on Github. diffstat: src/njs_builtin.c | 1 + src/njs_fs.c | 415 +++++++++++++++++++++++++++++++++++++++++++++ src/njs_fs.h | 1 + src/njs_vm.h | 3 +- src/test/njs_unit_test.c | 41 ++++ test/js/fs_promises_007.js | 231 +++++++++++++++++++++++++ test/njs_expect_test.exp | 14 +- 7 files changed, 696 insertions(+), 10 deletions(-) diffs (839 lines): diff -r 724dedc6be18 -r b33402f10e82 src/njs_builtin.c --- a/src/njs_builtin.c Tue Jun 09 12:56:56 2020 +0000 +++ b/src/njs_builtin.c Sun May 31 08:45:41 2020 +0300 @@ -73,6 +73,7 @@ static const njs_object_type_init_t *con /* Hidden types. */ + &njs_dirent_type_init, &njs_hash_type_init, &njs_hmac_type_init, &njs_typed_array_type_init, diff -r 724dedc6be18 -r b33402f10e82 src/njs_fs.c --- a/src/njs_fs.c Tue Jun 09 12:56:56 2020 +0000 +++ b/src/njs_fs.c Sun May 31 08:45:41 2020 +0300 @@ -7,6 +7,31 @@ #include +#include + +#if (NJS_SOLARIS) + +#define DT_DIR 0 +#define DT_REG 0 +#define DT_CHR 0 +#define DT_LNK 0 +#define DT_BLK 0 +#define DT_FIFO 0 +#define DT_SOCK 0 +#define NJS_DT_INVALID 0xffffffff + +#define njs_dentry_type(_dentry) \ + (NJS_DT_INVALID) + +#else + +#define NJS_DT_INVALID 0xffffffff + +#define njs_dentry_type(_dentry) \ + ((_dentry)->d_type) + +#endif + #define njs_fs_magic(calltype, mode) \ (((mode) << 2) | calltype) @@ -53,6 +78,8 @@ static njs_fs_encoding_t njs_fs_encoding static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback, const njs_value_t *args, njs_uint_t nargs); +static njs_int_t njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, + njs_value_t *type, njs_value_t *retval); static njs_fs_entry_t njs_flags_table[] = { { njs_str("r"), O_RDONLY }, @@ -895,6 +922,163 @@ njs_fs_rmdir(njs_vm_t *vm, njs_value_t * static njs_int_t +njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t calltype) +{ + DIR *dir; + u_char *d_name; + size_t size; + ssize_t length; + njs_int_t ret; + const char *dir_path; + njs_value_t encoding, types, ename, etype, retval, *path, *callback, + *options, *value; + njs_array_t *results; + struct dirent *entry; + njs_fs_encoding_t enc; + + static const njs_value_t string_encoding = njs_string("encoding"); + static const njs_value_t string_types = njs_string("withFileTypes"); + + path = njs_arg(args, nargs, 1); + ret = njs_fs_path_arg(vm, &dir_path, path, &njs_str_value("path")); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + callback = NULL; + options = njs_arg(args, nargs, 2); + + if (njs_slow_path(calltype == NJS_FS_CALLBACK)) { + callback = njs_arg(args, nargs, njs_min(nargs - 1, 3)); + if (!njs_is_function(callback)) { + njs_type_error(vm, "\"callback\" must be a function"); + return NJS_ERROR; + } + if (options == callback) { + options = njs_value_arg(&njs_value_undefined); + } + } + + njs_set_false(&types); + njs_set_undefined(&encoding); + + switch (options->type) { + case NJS_STRING: + encoding = *options; + break; + + case NJS_UNDEFINED: + break; + + default: + if (!njs_is_object(options)) { + njs_type_error(vm, "Unknown options type: \"%s\" " + "(a string or object required)", + njs_type_string(options->type)); + return NJS_ERROR; + } + + ret = njs_value_property(vm, options, njs_value_arg(&string_encoding), + &encoding); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + ret = njs_value_property(vm, options, njs_value_arg(&string_types), + &types); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + } + + enc = njs_fs_encoding(vm, &encoding); + if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) { + return NJS_ERROR; + } + + results = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE); + if (njs_slow_path(results == NULL)) { + return NJS_ERROR; + } + + njs_set_array(&retval, results); + + dir = opendir(dir_path); + if (njs_slow_path(dir == NULL)) { + ret = njs_fs_error(vm, "opendir", strerror(errno), path, errno, + &retval); + goto done; + } + + for ( ;; ) { + errno = 0; + entry = readdir(dir); + if (njs_slow_path(entry == NULL)) { + if (errno != 0) { + ret = njs_fs_error(vm, "readdir", strerror(errno), path, errno, + &retval); + } + + goto done; + } + + d_name = (u_char *) entry->d_name; + + size = njs_strlen(d_name); + length = njs_utf8_length(d_name, size); + if (njs_slow_path(length < 0)) { + length = 0; + } + + if ((length == 1 && d_name[0] == '.') + || (length == 2 && (d_name[0] == '.' && d_name[1] == '.'))) + { + continue; + } + + if (njs_fast_path(!njs_is_true(&types))) { + ret = njs_array_string_add(vm, results, d_name, size, length); + if (njs_slow_path(ret != NJS_OK)) { + goto done; + } + + continue; + } + + ret = njs_string_new(vm, &ename, d_name, size, length); + if (njs_slow_path(ret != NJS_OK)) { + goto done; + } + + njs_set_number(&etype, njs_dentry_type(entry)); + + value = njs_array_push(vm, results); + if (njs_slow_path(value == NULL)) { + goto done; + } + + ret = njs_fs_dirent_create(vm, &ename, &etype, value); + if (njs_slow_path(ret != NJS_OK)) { + goto done; + } + } + +done: + + if (dir != NULL) { + (void) closedir(dir); + } + + if (ret == NJS_OK) { + return njs_fs_result(vm, &retval, calltype, callback, 2); + } + + return NJS_ERROR; +} + + +static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data) { u_char *p, *end, *start; @@ -1231,6 +1415,205 @@ memory_error: } +static njs_int_t +njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type, + njs_value_t *retval) +{ + njs_int_t ret; + njs_object_t *object; + + static const njs_value_t string_name = njs_string("name"); + static const njs_value_t string_type = njs_string("type"); + + object = njs_object_alloc(vm); + if (njs_slow_path(object == NULL)) { + return NJS_ERROR; + } + + object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FS_DIRENT].object; + + njs_set_object(retval, object); + + ret = njs_value_property_set(vm, retval, njs_value_arg(&string_name), + name); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + /* TODO: use a private symbol as a key. */ + ret = njs_value_property_set(vm, retval, njs_value_arg(&string_type), + type); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + return NJS_OK; +} + + +static njs_int_t +njs_dirent_constructor(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused) +{ + if (njs_slow_path(!vm->top_frame->ctor)) { + njs_type_error(vm, "the Dirent constructor must be called with new"); + return NJS_ERROR; + } + + return njs_fs_dirent_create(vm, njs_arg(args, nargs, 1), + njs_arg(args, nargs, 2), &vm->retval); +} + + +static const njs_object_prop_t njs_dirent_constructor_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("Dirent"), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 2.0), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("prototype"), + .value = njs_prop_handler(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_dirent_constructor_init = { + njs_dirent_constructor_properties, + njs_nitems(njs_dirent_constructor_properties), +}; + + +static njs_int_t +njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t testtype) +{ + njs_int_t ret; + njs_value_t type, *this; + + static const njs_value_t string_type = njs_string("type"); + + this = njs_argument(args, 0); + + ret = njs_value_property(vm, this, njs_value_arg(&string_type), &type); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + if (njs_slow_path(njs_is_number(&type) + && (njs_number(&type) == NJS_DT_INVALID))) + { + njs_internal_error(vm, "dentry type is not supported on this platform"); + return NJS_ERROR; + } + + njs_set_boolean(&vm->retval, + njs_is_number(&type) && testtype == njs_number(&type)); + + return NJS_OK; +} + + +static const njs_object_prop_t njs_dirent_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), + .value = njs_string("Dirent"), + .configurable = 1, + }, + + { + .type = NJS_PROPERTY_HANDLER, + .name = njs_string("constructor"), + .value = njs_prop_handler(njs_object_prototype_create_constructor), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isDirectory"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_DIR), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isFile"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_REG), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isBlockDevice"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_BLK), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_long_string("isCharacterDevice"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_CHR), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isSymbolicLink"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_LNK), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isFIFO"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_FIFO), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("isSocket"), + .value = njs_native_function2(njs_fs_dirent_test, 0, DT_SOCK), + .writable = 1, + .configurable = 1, + }, +}; + + +const njs_object_init_t njs_dirent_prototype_init = { + njs_dirent_prototype_properties, + njs_nitems(njs_dirent_prototype_properties), +}; + + +const njs_object_type_init_t njs_dirent_type_init = { + .constructor = njs_native_ctor(njs_dirent_constructor, 2, 0), + .prototype_props = &njs_dirent_prototype_init, + .constructor_props = &njs_dirent_constructor_init, + .prototype_value = { .object = { .type = NJS_OBJECT } }, +}; + + static const njs_object_prop_t njs_fs_promises_properties[] = { { @@ -1293,6 +1676,14 @@ static const njs_object_prop_t njs_fs_p { .type = NJS_PROPERTY, + .name = njs_string("readdir"), + .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_PROMISE), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, .name = njs_string("symlink"), .value = njs_native_function2(njs_fs_symlink, 0, NJS_FS_PROMISE), .writable = 1, @@ -1399,6 +1790,14 @@ static const njs_object_prop_t njs_fs_o { .type = NJS_PROPERTY, + .name = njs_string("Dirent"), + .value = _njs_native_function(njs_dirent_constructor, 2, 1, 0), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, .name = njs_string("access"), .value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK), .writable = 1, @@ -1560,6 +1959,22 @@ static const njs_object_prop_t njs_fs_o .writable = 1, .configurable = 1, }, + + { + .type = NJS_PROPERTY, + .name = njs_string("readdir"), + .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_CALLBACK), + .writable = 1, + .configurable = 1, + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("readdirSync"), + .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_DIRECT), + .writable = 1, + .configurable = 1, + }, }; diff -r 724dedc6be18 -r b33402f10e82 src/njs_fs.h --- a/src/njs_fs.h Tue Jun 09 12:56:56 2020 +0000 +++ b/src/njs_fs.h Sun May 31 08:45:41 2020 +0300 @@ -10,5 +10,6 @@ extern const njs_object_init_t njs_fs_object_init; +extern const njs_object_type_init_t njs_dirent_type_init; #endif /* _NJS_FS_H_INCLUDED_ */ diff -r 724dedc6be18 -r b33402f10e82 src/njs_vm.h --- a/src/njs_vm.h Tue Jun 09 12:56:56 2020 +0000 +++ b/src/njs_vm.h Sun May 31 08:45:41 2020 +0300 @@ -92,8 +92,9 @@ typedef enum { NJS_OBJ_TYPE_PROMISE, NJS_OBJ_TYPE_ARRAY_BUFFER, + NJS_OBJ_TYPE_FS_DIRENT, +#define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_FS_DIRENT) NJS_OBJ_TYPE_CRYPTO_HASH, -#define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_CRYPTO_HASH) NJS_OBJ_TYPE_CRYPTO_HMAC, NJS_OBJ_TYPE_TYPED_ARRAY, #define NJS_OBJ_TYPE_HIDDEN_MAX (NJS_OBJ_TYPE_TYPED_ARRAY + 1) diff -r 724dedc6be18 -r b33402f10e82 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 09 12:56:56 2020 +0000 +++ b/src/test/njs_unit_test.c Sun May 31 08:45:41 2020 +0300 @@ -16371,12 +16371,20 @@ static njs_unit_test_t njs_test[] = "'writeFileSync'," "'appendFile'," "'appendFileSync'," + "'rename'," + "'renameSync'," "'symlink'," "'symlinkSync'," "'unlink'," "'unlinkSync'," "'realpath'," "'realpathSync'," + "'mkdir'," + "'mkdirSync'," + "'rmdir'," + "'rmdirSync'," + "'readdir'," + "'readdirSync'," "]," "test = (fname) =>" "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]" @@ -16399,9 +16407,13 @@ static njs_unit_test_t njs_test[] = "'readFile'," "'writeFile'," "'appendFile'," + "'rename'," "'symlink'," "'unlink'," "'realpath'," + "'mkdir'," + "'rmdir'," + "'readdir'," "];" "func.every((x) => typeof fs[x] == 'function')"), njs_str("true")}, @@ -16423,6 +16435,35 @@ static njs_unit_test_t njs_test[] = "items.every((x) => typeof fsc[x] == 'number')"), njs_str("true")}, + /* require('fs').Dirent */ + + { njs_str("var fs = require('fs');" + "typeof fs.Dirent"), + njs_str("function") }, + + { njs_str("var fs = require('fs');" + "fs.Dirent('file', 123)"), + njs_str("TypeError: the Dirent constructor must be called with new") }, + + { njs_str("var fs = require('fs');" + "var e = new fs.Dirent('file', 123); [e.name, e.type]"), + njs_str("file,123") }, + + { njs_str("var " + "fs = require('fs')," + "e = new fs.Dirent('file', 0)," + "func = [" + "'isDirectory'," + "'isFile'," + "'isBlockDevice'," + "'isCharacterDevice'," + "'isSymbolicLink'," + "'isFIFO'," + "'isSocket'," + "];" + "func.every((x) => typeof e[x] == 'function')"), + njs_str("true")}, + /* require('crypto').createHash() */ { njs_str("var h = require('crypto').createHash('sha1');" diff -r 724dedc6be18 -r b33402f10e82 test/js/fs_promises_007.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/js/fs_promises_007.js Sun May 31 08:45:41 2020 +0300 @@ -0,0 +1,231 @@ +var fs = require('fs'); +var fsp = fs.promises; +var dname = './build/test/fs_promises_007'; +var dname_utf8 = './build/test/fs_promises_???_007'; +var fname = (d) => d + '/fs_promises_007_file'; +var lname = (d) => d + '/fs_promises_007_link'; +var cname = (d) => d + '/fs_promises_???_007_dir'; + + +var dir_test = [cname(''), lname(''), fname('')].map((x) => x.substring(1)); +var match = (entry) => { + var idx = dir_test.indexOf(entry.name); + + try { + switch(idx) { + case 0: + return entry.isDirectory(); + case 1: + return entry.isSymbolicLink(); + case 2: + return entry.isFile(); + default: + return false; + } + } catch (e) { + if (e.name == 'InternalError') { + return true; + } + + throw e; + } +}; + + +var testSync = () => new Promise((resolve, reject) => { + try { + try { fs.rmdirSync(cname(dname)); } catch (e) {} + try { fs.rmdirSync(cname(dname_utf8)); } catch (e) {} + try { fs.unlinkSync(lname(dname)); } catch (e) {} + try { fs.unlinkSync(lname(dname_utf8)); } catch (e) {} + try { fs.unlinkSync(fname(dname)); } catch (e) {} + try { fs.unlinkSync(fname(dname_utf8)); } catch (e) {} + try { fs.rmdirSync(dname); } catch (e) {} + try { fs.rmdirSync(dname_utf8); } catch (e) {} + + try { + fs.readdirSync(dname); + throw new Error('fs.readdirSync - error 0'); + + } catch (e) { + if (e.code != 'ENOENT') { + // njs: e.syscall == 'opendir' + // node: e.syscall == 'scandir' + throw e; + } + } + + fs.mkdirSync(dname); + fs.mkdirSync(dname_utf8); + fs.writeFileSync(fname(dname), fname(dname)); + fs.writeFileSync(fname(dname_utf8), fname(dname_utf8)); + fs.symlinkSync(fname('.'), lname(dname)); + fs.symlinkSync(fname('.'), lname(dname_utf8)); + fs.mkdirSync(cname(dname)); + fs.mkdirSync(cname(dname_utf8)); + + var dir = fs.readdirSync(dname); + var dir_utf8 = fs.readdirSync(dname_utf8); + if (dir.length != dir_utf8.length || dir.length != 3) { + throw new Error('fs.readdirSync - error 1'); + } + + var test = dir.filter((x) => !dir_test.includes(x)); + if (test.length != 0) { + throw new Error('fs.readdirSync - error 2'); + } + + var test = dir_utf8.filter((x) => !dir_test.includes(x)); + if (test.length != 0) { + throw new Error('fs.readdirSync - error 3'); + } + + var dir = fs.readdirSync(dname, { withFileTypes: true }); + var dir_utf8 = fs.readdirSync(dname_utf8, { withFileTypes: true }); + if (dir.length != dir_utf8.length || dir.length != 3) { + throw new Error('fs.readdirSync - error 4'); + } + + var test = dir.filter((x) => !match(x)); + if (test.length != 0) { + throw new Error('fs.readdirSync - error 5'); + } + + var test = dir_utf8.filter((x) => !match(x)); + if (test.length != 0) { + throw new Error('fs.readdirSync - error 6'); + } + + resolve(); + + } catch (e) { + reject(e); + } +}); + + +var testCallback = () => new Promise((resolve, reject) => { + try { + try { fs.rmdirSync(cname(dname)); } catch (e) {} + try { fs.unlinkSync(lname(dname)); } catch (e) {} + try { fs.unlinkSync(fname(dname)); } catch (e) {} + try { fs.rmdirSync(dname); } catch (e) {} + + fs.readdir(dname, (err, files) => { + if (!err || err.code != 'ENOENT') { + reject(new Error('fs.readdir - error 1')); + } + + try { + fs.mkdirSync(dname); + fs.writeFileSync(fname(dname), fname(dname)); + fs.symlinkSync(fname('.'), lname(dname)); + fs.mkdirSync(cname(dname)); + + } catch (e) { + reject(e); + } + + fs.readdir(dname, (err, dir) => { + if (err) { + reject(err); + } + + if (dir.length != 3) { + reject(new Error('fs.readdir - error 2')); + } + + var test = dir.filter((x) => !dir_test.includes(x)); + if (test.length != 0) { + reject(new Error('fs.readdir - error 3')); + } + + fs.readdir(dname, { withFileTypes: true }, (err, dir) => { + if (err) { + reject(err); + } + + if (dir.length != 3) { + reject(new Error('fs.readdir - error 4')); + } + + var test = dir.filter((x) => !match(x)); + if (test.length != 0) { + reject(new Error('fs.readdir - error 5')); + } + + resolve(); + }); + }); + }); + + } catch (e) { + reject(e); + } +}); + + +Promise.resolve() +.then(testSync) +.then(() => { + console.log('test fs.readdirSync'); +}) +.catch((e) => { + console.log('test fs.readdirSync failed', JSON.stringify(e)); +}) + +.then(testCallback) +.then(() => { + console.log('test fs.readdir'); +}) +.catch((e) => { + console.log('test fs.readdir failed', JSON.stringify(e)); +}) + +.then(() => { + try { fs.rmdirSync(cname(dname)); } catch (e) {} + try { fs.unlinkSync(lname(dname)); } catch (e) {} + try { fs.unlinkSync(fname(dname)); } catch (e) {} + try { fs.rmdirSync(dname); } catch (e) {} +}) +.then(() => fsp.readdir(dname) + .then(() => { throw new Error('fsp.readdir - error 1'); })) +.catch((e) => { + if (e.code != 'ENOENT') { + throw e; + } +}) +.then(() => { + fs.mkdirSync(dname); + fs.writeFileSync(fname(dname), fname(dname)); + fs.symlinkSync(fname('.'), lname(dname)); + fs.mkdirSync(cname(dname)); +}) +.then(() => fsp.readdir(dname)) +.then((dir) => { + if (dir.length != 3) { + throw new Error('fsp.readdir - error 2'); + } + + var test = dir.filter((x) => !dir_test.includes(x)); + if (test.length != 0) { + throw new Error('fsp.readdir - error 3'); + } +}) +.then(() => fsp.readdir(dname, { withFileTypes: true })) +.then((dir) => { + if (dir.length != 3) { + throw new Error('fsp.readdir - error 4'); + } + + var test = dir.filter((x) => !match(x)); + if (test.length != 0) { + throw new Error('fsp.readdir - error 5'); + } +}) +.then(() => { + console.log('test fsp.readdir'); +}) +.catch((e) => { + console.log('test fsp.readdir failed', JSON.stringify(e)); +}); diff -r 724dedc6be18 -r b33402f10e82 test/njs_expect_test.exp --- a/test/njs_expect_test.exp Tue Jun 09 12:56:56 2020 +0000 +++ b/test/njs_expect_test.exp Sun May 31 08:45:41 2020 +0300 @@ -459,15 +459,6 @@ njs_test { "queue.toString()\r\n'0,1,2,3,4,5'"} } -# require('fs') - -njs_test { - {"var fs = require('fs')\r\n" - "undefined\r\n>> "} - {"fs.read\t" - "fs.read\a*File"} -} - # require('fs').readFile() njs_test { @@ -1144,3 +1135,8 @@ njs_run {"./test/js/fs_promises_006.js"} "test fs.renameSync test fs.rename test fsp.rename" + +njs_run {"./test/js/fs_promises_007.js"} \ +"test fs.readdirSync +test fs.readdir +test fsp.readdir" From vl at nginx.com Tue Jun 9 19:04:03 2020 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 09 Jun 2020 19:04:03 +0000 Subject: [nginx] Stream: fixed processing of zero length UDP packets (ticket #1982). Message-ID: details: https://hg.nginx.org/nginx/rev/d127837c714f branches: changeset: 7665:d127837c714f user: Vladimir Homutov date: Mon Jun 08 11:40:34 2020 +0300 description: Stream: fixed processing of zero length UDP packets (ticket #1982). diffstat: src/os/unix/ngx_udp_sendmsg_chain.c | 7 +++++++ src/stream/ngx_stream_proxy_module.c | 3 ++- src/stream/ngx_stream_write_filter_module.c | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diffs (50 lines): diff -r 699f6e55bbb4 -r d127837c714f src/os/unix/ngx_udp_sendmsg_chain.c --- a/src/os/unix/ngx_udp_sendmsg_chain.c Wed Jun 03 19:11:32 2020 +0300 +++ b/src/os/unix/ngx_udp_sendmsg_chain.c Mon Jun 08 11:40:34 2020 +0300 @@ -189,6 +189,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_ return cl; } + /* zero-sized datagram; pretend to have at least 1 iov */ + if (n == 0) { + iov = &vec->iovs[n++]; + iov->iov_base = NULL; + iov->iov_len = 0; + } + vec->count = n; vec->size = total; diff -r 699f6e55bbb4 -r d127837c714f src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Wed Jun 03 19:11:32 2020 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Mon Jun 08 11:40:34 2020 +0300 @@ -839,7 +839,7 @@ ngx_stream_proxy_init_upstream(ngx_strea u->upstream_buf.last = p; } - if (c->buffer && c->buffer->pos < c->buffer->last) { + if (c->buffer && c->buffer->pos <= c->buffer->last) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream proxy add preread buffer: %uz", c->buffer->last - c->buffer->pos); @@ -853,6 +853,7 @@ ngx_stream_proxy_init_upstream(ngx_strea *cl->buf = *c->buffer; cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; + cl->buf->temporary = (cl->buf->pos == cl->buf->last) ? 0 : 1; cl->buf->flush = 1; cl->next = u->upstream_out; diff -r 699f6e55bbb4 -r d127837c714f src/stream/ngx_stream_write_filter_module.c --- a/src/stream/ngx_stream_write_filter_module.c Wed Jun 03 19:11:32 2020 +0300 +++ b/src/stream/ngx_stream_write_filter_module.c Mon Jun 08 11:40:34 2020 +0300 @@ -234,7 +234,8 @@ ngx_stream_write_filter(ngx_stream_sessi if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) - && !(last && c->need_last_buf)) + && !(last && c->need_last_buf) + && !(c->type == SOCK_DGRAM && flush)) { if (last || flush || sync) { for (cl = *out; cl; /* void */) { From yigal.edery at kameleonsec.com Wed Jun 10 12:11:00 2020 From: yigal.edery at kameleonsec.com (Yigal Edery) Date: Wed, 10 Jun 2020 12:11:00 +0000 Subject: nginx test plan with max coverage? In-Reply-To: References: Message-ID: Anyone? From: Yigal Edery Sent: Thursday, June 4, 2020 20:54 To: nginx-devel at nginx.org Subject: nginx test plan with max coverage? Hi I hope this is the right forum to ask. I need to set up NGINX and run a full test coverage on it. Other than the nginx-tests, is there some formal test plan for nginx that you use, to exercises an nginx server before declaring a release? I am thinking some long duration tests with maximum code coverage and stability tests... Thanks, Yigal -------------- next part -------------- An HTML attachment was scrubbed... URL: From maxim at nginx.com Wed Jun 10 12:18:12 2020 From: maxim at nginx.com (Maxim Konovalov) Date: Wed, 10 Jun 2020 15:18:12 +0300 Subject: nginx test plan with max coverage? In-Reply-To: References: Message-ID: <7cc9f12c-28bd-2bd1-3774-23247844d449@nginx.com> Hi Yigal, We use nginx-tests for that. The suite provides "good enough" coverage already which is also monitored by the development team. Maxim On 10.06.2020 15:11, Yigal Edery wrote: > Anyone? > > ? > > *From:* Yigal Edery > *Sent:* Thursday, June 4, 2020 20:54 > *To:* nginx-devel at nginx.org > *Subject:* nginx test plan with max coverage? > > ? > > Hi > > ? > > I hope this is the right forum to ask. > > ? > > I need to set up NGINX and run a full test coverage on it. > > ? > > Other than the nginx-tests, is there some formal test plan for nginx > that you use, to exercises an nginx server before declaring a release? I > am thinking some long duration tests with maximum code coverage and > stability tests... > > ? > > Thanks, > > ? > > Yigal > > ? > > ? > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -- Maxim Konovalov From yigal.edery at kameleonsec.com Wed Jun 10 12:26:39 2020 From: yigal.edery at kameleonsec.com (Yigal Edery) Date: Wed, 10 Jun 2020 12:26:39 +0000 Subject: nginx test plan with max coverage? In-Reply-To: <7cc9f12c-28bd-2bd1-3774-23247844d449@nginx.com> References: <7cc9f12c-28bd-2bd1-3774-23247844d449@nginx.com> Message-ID: Thanks! Maybe we're doing something wrong... In our runs, nginx-tests ends running thru all the tests in just a few minutes. Is this as expected? -----Original Message----- From: Maxim Konovalov Sent: Wednesday, June 10, 2020 15:18 To: nginx-devel at nginx.org Cc: Yigal Edery Subject: Re: nginx test plan with max coverage? Hi Yigal, We use nginx-tests for that. The suite provides "good enough" coverage already which is also monitored by the development team. Maxim On 10.06.2020 15:11, Yigal Edery wrote: > Anyone? > > ? > > *From:* Yigal Edery > *Sent:* Thursday, June 4, 2020 20:54 > *To:* nginx-devel at nginx.org > *Subject:* nginx test plan with max coverage? > > ? > > Hi > > ? > > I hope this is the right forum to ask. > > ? > > I need to set up NGINX and run a full test coverage on it. > > ? > > Other than the nginx-tests, is there some formal test plan for nginx > that you use, to exercises an nginx server before declaring a release? > I am thinking some long duration tests with maximum code coverage and > stability tests... > > ? > > Thanks, > > ? > > Yigal > > ? > > ? > > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -- Maxim Konovalov From maxim at nginx.com Wed Jun 10 12:28:03 2020 From: maxim at nginx.com (Maxim Konovalov) Date: Wed, 10 Jun 2020 15:28:03 +0300 Subject: nginx test plan with max coverage? In-Reply-To: References: <7cc9f12c-28bd-2bd1-3774-23247844d449@nginx.com> Message-ID: Yes, that's fine. You can run an arbitrary number of iteration of these tests if needed. On 10.06.2020 15:26, Yigal Edery wrote: > Thanks! > > Maybe we're doing something wrong... In our runs, nginx-tests ends running thru all the tests in just a few minutes. Is this as expected? > > -----Original Message----- > From: Maxim Konovalov > Sent: Wednesday, June 10, 2020 15:18 > To: nginx-devel at nginx.org > Cc: Yigal Edery > Subject: Re: nginx test plan with max coverage? > > Hi Yigal, > > We use nginx-tests for that. The suite provides "good enough" coverage already which is also monitored by the development team. > > Maxim > > On 10.06.2020 15:11, Yigal Edery wrote: >> Anyone? >> >> ? >> >> *From:* Yigal Edery >> *Sent:* Thursday, June 4, 2020 20:54 >> *To:* nginx-devel at nginx.org >> *Subject:* nginx test plan with max coverage? >> >> ? >> >> Hi >> >> ? >> >> I hope this is the right forum to ask. >> >> ? >> >> I need to set up NGINX and run a full test coverage on it. >> >> ? >> >> Other than the nginx-tests, is there some formal test plan for nginx >> that you use, to exercises an nginx server before declaring a release? >> I am thinking some long duration tests with maximum code coverage and >> stability tests... >> >> ? >> >> Thanks, >> >> ? >> >> Yigal >> >> ? >> >> ? >> >> >> _______________________________________________ >> nginx-devel mailing list >> nginx-devel at nginx.org >> http://mailman.nginx.org/mailman/listinfo/nginx-devel >> > > > -- > Maxim Konovalov > -- Maxim Konovalov From osa at freebsd.org.ru Wed Jun 10 16:15:58 2020 From: osa at freebsd.org.ru (Sergey A. Osokin) Date: Wed, 10 Jun 2020 19:15:58 +0300 Subject: nginx test plan with max coverage? In-Reply-To: References: Message-ID: <20200610161558.GA86017@FreeBSD.org.ru> Hi Yigal, hope you're doing well these days. I've prepared this email some days ago, but I've just realised I haven't sent it yet. I do apologies for that. There're many tools are available on the market for static and dynamic analysis, code coverage and testing, including but not limiting by Coverity, VeraCode, SonarQube. The nginx-tests suite in most cases is for functional testing of the product. nginx is the open source project and it doesn't limit its customers to use any other tool to do a performance or functional testing, so it's possible to setup and configure a favorite tool and create a test suite for any needs in every particular case. Please let me know if you have any questions. -- Sergey On Thu, Jun 04, 2020 at 05:53:50PM +0000, Yigal Edery wrote: > Hi > > I hope this is the right forum to ask. > > I need to set up NGINX and run a full test coverage on it. > > Other than the nginx-tests, is there some formal test plan for nginx that you use, to exercises an nginx server before declaring a release? I am thinking some long duration tests with maximum code coverage and stability tests... > > Thanks, > > Yigal From jan.prachar at gmail.com Fri Jun 12 09:41:09 2020 From: jan.prachar at gmail.com (Jan =?UTF-8?Q?Pracha=C5=99?=) Date: Fri, 12 Jun 2020 11:41:09 +0200 Subject: nginx-quic & reload Message-ID: <97f2f1c1e24b40ff403148a5cc654ebfc5e8ce70.camel@gmail.com> Hello, I checked code at the nginx-quic repo and I can't see how the following problem is addressed. When nginx reloads config, new workers are created and they inhertis receiving sockets from the old workers. That means that the new workers will start processing packets of the quic connections of the old workers. But the new workers lack context for them, so they will ignore the packets and quic connection will timeout, right? A similar problem exists when a binary is changed. Do I miss something or will it be solved in the future? Unfortunatelly I cannot see any simple solution to this, because when a number of sockets in reuseport changes, kernel starts routing the same 4-tuple packets to a different socket. Best regards, Jan From eran.kornblau at kaltura.com Mon Jun 15 08:48:41 2020 From: eran.kornblau at kaltura.com (Eran Kornblau) Date: Mon, 15 Jun 2020 08:48:41 +0000 Subject: [PATCH] Fixed potential leak of temp pool. Message-ID: Hi Something I noticed today while looking at the code, it probably won't matter to anyone ever... But just sending for the sake of perfection :) Thanks! Eran -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: nginx-fix-temp-pool-leak.patch Type: application/octet-stream Size: 1098 bytes Desc: nginx-fix-temp-pool-leak.patch URL: From xeioex at nginx.com Mon Jun 15 15:27:13 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 15 Jun 2020 15:27:13 +0000 Subject: [njs] Fixed potential memory corruption in njs_function_frame_invoke(). Message-ID: details: https://hg.nginx.org/njs/rev/cf85ed422623 branches: changeset: 1430:cf85ed422623 user: Dmitry Volyntsev date: Mon Jun 15 15:26:40 2020 +0000 description: Fixed potential memory corruption in njs_function_frame_invoke(). It is a bug to cast vm->top_frame which is (njs_native_frame_t *) type, to (njs_frame_t *) in general context. The cast is allowed only for the lambda frames. The bug did not manifest itself previously because native frames were allocated with NJS_NATIVE_FRAME_SIZE, which is sizeof(njs_value_t) aligned size of njs_native_frame_t (on 64bit platform are 80 and 72 bytes respectively). njs_frame_t contains njs_native_frame_t as a first field. The frame->retval assignment for native frames resulted in 8 padding bytes were used as a storage space for the retval field. The bug becomes visible when the size of njs_native_frame_t changes. The issue was introduced in 540f03725df2. diffstat: src/njs_function.c | 24 +++++++++++------------- src/njs_function.h | 15 ++++----------- src/njs_promise.c | 18 +++++++++--------- src/njs_vm.c | 14 ++++++++------ src/njs_vm.h | 2 +- src/njs_vmcode.c | 10 +++++----- 6 files changed, 38 insertions(+), 45 deletions(-) diffs (294 lines): diff -r b33402f10e82 -r cf85ed422623 src/njs_function.c --- a/src/njs_function.c Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_function.c Mon Jun 15 15:26:40 2020 +0000 @@ -677,13 +677,11 @@ njs_function_native_call(njs_vm_t *vm) { njs_int_t ret; njs_value_t *value; - njs_frame_t *frame; njs_function_t *function, *target; njs_native_frame_t *native, *previous; njs_function_native_t call; native = vm->top_frame; - frame = (njs_frame_t *) native; function = native->function; if (njs_fast_path(function->bound == NULL)) { @@ -711,10 +709,10 @@ njs_function_native_call(njs_vm_t *vm) previous = njs_function_previous_frame(native); - njs_vm_scopes_restore(vm, frame, previous); + njs_vm_scopes_restore(vm, native, previous); if (!native->skip) { - value = njs_vmcode_operand(vm, frame->retval); + value = njs_vmcode_operand(vm, native->retval); /* * GC: value external/internal++ depending * on vm->retval and retval type @@ -1035,10 +1033,10 @@ static njs_int_t njs_function_prototype_call(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_int_t ret; - njs_frame_t *frame; - njs_function_t *function; - const njs_value_t *this; + njs_int_t ret; + njs_function_t *function; + const njs_value_t *this; + njs_native_frame_t *frame; if (!njs_is_function(&args[0])) { njs_type_error(vm, "\"this\" argument is not a function"); @@ -1054,13 +1052,13 @@ njs_function_prototype_call(njs_vm_t *vm nargs = 0; } - frame = (njs_frame_t *) vm->top_frame; + frame = vm->top_frame; + + /* Skip the "call" method frame. */ + frame->skip = 1; function = njs_function(&args[0]); - /* Skip the "call" method frame. */ - vm->top_frame->skip = 1; - ret = njs_function_frame(vm, function, this, &args[2], nargs, 0); if (njs_slow_path(ret != NJS_OK)) { return ret; @@ -1144,7 +1142,7 @@ activate: return ret; } - ret = njs_function_frame_invoke(vm, frame->retval); + ret = njs_function_frame_invoke(vm, frame->native.retval); if (njs_slow_path(ret != NJS_OK)) { return ret; } diff -r b33402f10e82 -r cf85ed422623 src/njs_function.h --- a/src/njs_function.h Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_function.h Mon Jun 15 15:26:40 2020 +0000 @@ -39,10 +39,6 @@ struct njs_function_lambda_s { njs_align_size(sizeof(njs_frame_t) + closures * sizeof(njs_closure_t *), \ sizeof(njs_value_t)) -/* The retval field is not used in the global frame. */ -#define NJS_GLOBAL_FRAME_SIZE \ - njs_align_size(offsetof(njs_frame_t, retval), sizeof(njs_value_t)) - #define NJS_FRAME_SPARE_SIZE 512 @@ -68,6 +64,7 @@ struct njs_native_frame_s { njs_object_t *arguments_object; njs_exception_t exception; + njs_index_t retval; uint32_t size; uint32_t free_size; @@ -84,9 +81,6 @@ struct njs_native_frame_s { struct njs_frame_s { njs_native_frame_t native; - njs_index_t retval; - - u_char *return_address; njs_frame_t *previous_active_frame; njs_value_t *local; @@ -170,13 +164,12 @@ njs_function_previous_frame(njs_native_f njs_inline njs_int_t njs_function_frame_invoke(njs_vm_t *vm, njs_index_t retval) { - njs_frame_t *frame; + njs_native_frame_t *frame; - frame = (njs_frame_t *) vm->top_frame; - + frame = vm->top_frame; frame->retval = retval; - if (frame->native.function->native) { + if (frame->function->native) { return njs_function_native_call(vm); } else { diff -r b33402f10e82 -r cf85ed422623 src/njs_promise.c --- a/src/njs_promise.c Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_promise.c Mon Jun 15 15:26:40 2020 +0000 @@ -559,16 +559,16 @@ njs_promise_resolve_function(njs_vm_t *v njs_index_t unused) { njs_int_t ret; - njs_frame_t *active_frame; njs_value_t *resolution, error, then, arguments[3]; njs_promise_t *promise; njs_function_t *function; + njs_native_frame_t *active_frame; njs_promise_context_t *context; static const njs_value_t string_then = njs_string("then"); - active_frame = (njs_frame_t *) vm->top_frame; - context = active_frame->native.function->context; + active_frame = vm->top_frame; + context = active_frame->function->context; promise = njs_promise(&context->promise); if (*context->resolved_ref) { @@ -715,12 +715,12 @@ static njs_int_t njs_promise_reject_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - njs_frame_t *active_frame; njs_value_t *value; + njs_native_frame_t *active_frame; njs_promise_context_t *context; - active_frame = (njs_frame_t *) vm->top_frame; - context = active_frame->native.function->context; + active_frame = vm->top_frame; + context = active_frame->function->context; if (*context->resolved_ref) { njs_vm_retval_set(vm, &njs_value_undefined); @@ -995,12 +995,12 @@ njs_promise_then_finally_function(njs_vm { njs_int_t ret; njs_value_t value, retval; - njs_frame_t *frame; njs_promise_t *promise; + njs_native_frame_t *frame; njs_promise_context_t *context; - frame = (njs_frame_t *) vm->top_frame; - context = frame->native.function->context; + frame = vm->top_frame; + context = frame->function->context; ret = njs_function_call(vm, njs_function(&context->finally), &njs_value_undefined, args, 0, &retval); diff -r b33402f10e82 -r cf85ed422623 src/njs_vm.c --- a/src/njs_vm.c Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_vm.c Mon Jun 15 15:26:40 2020 +0000 @@ -286,7 +286,7 @@ njs_vm_init(njs_vm_t *vm) scope_size = vm->scope_size + NJS_INDEX_GLOBAL_OFFSET; - size = NJS_GLOBAL_FRAME_SIZE + scope_size + NJS_FRAME_SPARE_SIZE; + size = njs_frame_size(0) + scope_size + NJS_FRAME_SPARE_SIZE; size = njs_align_size(size, NJS_FRAME_SPARE_SIZE); frame = njs_mp_align(vm->mem_pool, sizeof(njs_value_t), size); @@ -294,15 +294,15 @@ njs_vm_init(njs_vm_t *vm) return NJS_ERROR; } - njs_memzero(frame, NJS_GLOBAL_FRAME_SIZE); + njs_memzero(frame, njs_frame_size(0)); vm->top_frame = &frame->native; vm->active_frame = frame; frame->native.size = size; - frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size); + frame->native.free_size = size - (njs_frame_size(0) + scope_size); - values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE; + values = (u_char *) frame + njs_frame_size(0); frame->native.free = values + scope_size; @@ -357,11 +357,12 @@ njs_vm_invoke(njs_vm_t *vm, njs_function void -njs_vm_scopes_restore(njs_vm_t *vm, njs_frame_t *frame, +njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *native, njs_native_frame_t *previous) { njs_uint_t n, nesting; njs_value_t *args; + njs_frame_t *frame; njs_closure_t **closures; njs_function_t *function; @@ -376,7 +377,7 @@ njs_vm_scopes_restore(njs_vm_t *vm, njs_ vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = args; - function = frame->native.function; + function = native->function; if (function->native) { return; @@ -386,6 +387,7 @@ njs_vm_scopes_restore(njs_vm_t *vm, njs_ /* GC: release function closures. */ } + frame = (njs_frame_t *) native; frame = frame->previous_active_frame; vm->active_frame = frame; diff -r b33402f10e82 -r cf85ed422623 src/njs_vm.h --- a/src/njs_vm.h Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_vm.h Mon Jun 15 15:26:40 2020 +0000 @@ -286,7 +286,7 @@ struct njs_vm_shared_s { }; -void njs_vm_scopes_restore(njs_vm_t *vm, njs_frame_t *frame, +void njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *frame, njs_native_frame_t *previous); njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack, njs_native_frame_t *native_frame); diff -r b33402f10e82 -r cf85ed422623 src/njs_vmcode.c --- a/src/njs_vmcode.c Sun May 31 08:45:41 2020 +0300 +++ b/src/njs_vmcode.c Mon Jun 15 15:26:40 2020 +0000 @@ -705,13 +705,13 @@ next: previous = njs_function_previous_frame(&frame->native); - njs_vm_scopes_restore(vm, frame, previous); + njs_vm_scopes_restore(vm, &frame->native, previous); /* * If a retval is in a callee arguments scope it * must be in the previous callee arguments scope. */ - retval = njs_vmcode_operand(vm, frame->retval); + retval = njs_vmcode_operand(vm, frame->native.retval); /* * GC: value external/internal++ depending on @@ -923,7 +923,7 @@ error: lambda_call = (frame == vm->active_frame); - njs_vm_scopes_restore(vm, frame, previous); + njs_vm_scopes_restore(vm, &frame->native, previous); if (frame->native.size != 0) { vm->stack_size -= frame->native.size; @@ -1687,13 +1687,13 @@ njs_vmcode_return(njs_vm_t *vm, njs_valu previous = njs_function_previous_frame(&frame->native); - njs_vm_scopes_restore(vm, frame, previous); + njs_vm_scopes_restore(vm, &frame->native, previous); /* * If a retval is in a callee arguments scope it * must be in the previous callee arguments scope. */ - retval = njs_vmcode_operand(vm, frame->retval); + retval = njs_vmcode_operand(vm, frame->native.retval); /* GC: value external/internal++ depending on value and retval type */ *retval = *value; From xeioex at nginx.com Mon Jun 15 15:27:15 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 15 Jun 2020 15:27:15 +0000 Subject: [njs] Merging interactive tests into unit_test binary. Message-ID: details: https://hg.nginx.org/njs/rev/6023201cf1f3 branches: changeset: 1431:6023201cf1f3 user: Dmitry Volyntsev date: Mon Jun 15 15:26:44 2020 +0000 description: Merging interactive tests into unit_test binary. diffstat: auto/make | 4 +- auto/sources | 1 - src/test/njs_interactive_test.c | 406 ---------------------------------------- src/test/njs_unit_test.c | 377 +++++++++++++++++++++++++++++++++++++ 4 files changed, 378 insertions(+), 410 deletions(-) diffs (837 lines): diff -r cf85ed422623 -r 6023201cf1f3 auto/make --- a/auto/make Mon Jun 15 15:26:40 2020 +0000 +++ b/auto/make Mon Jun 15 15:26:44 2020 +0000 @@ -249,11 +249,9 @@ lib_test: $NJS_BUILD_DIR/njs_auto_config $NJS_BUILD_DIR/utf8_unit_test unit_test: $NJS_BUILD_DIR/njs_auto_config.h \\ - $NJS_BUILD_DIR/njs_unit_test \\ - $NJS_BUILD_DIR/njs_interactive_test + $NJS_BUILD_DIR/njs_unit_test $NJS_BUILD_DIR/njs_unit_test - $NJS_BUILD_DIR/njs_interactive_test test: expect_test unit_test diff -r cf85ed422623 -r 6023201cf1f3 auto/sources --- a/auto/sources Mon Jun 15 15:26:40 2020 +0000 +++ b/auto/sources Mon Jun 15 15:26:44 2020 +0000 @@ -65,6 +65,5 @@ NJS_LIB_TEST_SRCS=" \ NJS_TEST_SRCS=" \ src/test/njs_unit_test.c \ - src/test/njs_interactive_test.c \ src/test/njs_benchmark.c \ " diff -r cf85ed422623 -r 6023201cf1f3 src/test/njs_interactive_test.c --- a/src/test/njs_interactive_test.c Mon Jun 15 15:26:40 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,406 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - -#include - -#include -#include -#include - -#include "njs_externals_test.h" - - -typedef struct { - njs_str_t script; - njs_str_t ret; -} njs_interactive_test_t; - - -#define ENTER "\n\3" - - -static njs_interactive_test_t njs_test[] = -{ - { njs_str("var a = 3" ENTER - "a * 2" ENTER), - njs_str("6") }, - - { njs_str("var a = \"aa\\naa\"" ENTER - "a" ENTER), - njs_str("aa\naa") }, - - { njs_str("var a = 3" ENTER - "var a = 'str'" ENTER - "a" ENTER), - njs_str("str") }, - - { njs_str("var a = 2" ENTER - "a *= 2" ENTER - "a *= 2" ENTER - "a *= 2" ENTER), - njs_str("16") }, - - { njs_str("var a = 2" ENTER - "var b = 3" ENTER - "a * b" ENTER), - njs_str("6") }, - - { njs_str("var a = 2; var b = 3;" ENTER - "a * b" ENTER), - njs_str("6") }, - - { njs_str("function sq(f) { return f() * f() }" ENTER - "sq(function () { return 3 })" ENTER), - njs_str("9") }, - - /* Temporary indexes */ - - { njs_str("var a = [1,2,3], i; for (i in a) {Object.seal({});}" ENTER), - njs_str("undefined") }, - - { njs_str("var i; for (i in [1,2,3]) {Object.seal({});}" ENTER), - njs_str("undefined") }, - - { njs_str("var a = 'A'; switch (a) {" - "case 0: a += '0';" - "case 1: a += '1';" - "}; a" ENTER), - njs_str("A") }, - - { njs_str("var a = 0; try { a = 5 }" - "catch (e) { a = 9 } finally { a++ } a" ENTER), - njs_str("6") }, - - { njs_str("/abc/i.test('ABC')" ENTER), - njs_str("true") }, - - /* Accumulative mode. */ - - { njs_str("var a = 1" ENTER - "a" ENTER), - njs_str("1") }, - - { njs_str("Number.prototype.test = 'test'" ENTER - "Number.prototype.test" ENTER), - njs_str("test") }, - - /* Error handling */ - - { njs_str("var a = ;" ENTER - "2 + 2" ENTER), - njs_str("4") }, - - { njs_str("function f() { return b;" ENTER), - njs_str("SyntaxError: Unexpected end of input in 1") }, - - { njs_str("function f() { return b;" ENTER - "2 + 2" ENTER), - njs_str("4") }, - - { njs_str("function f() { return function() { return 1" ENTER - "2 + 2" ENTER), - njs_str("4") }, - - { njs_str("function f() { return b;}" ENTER - "2 + 2" ENTER), - njs_str("4") }, - - { njs_str("function f(o) { return o.a.a;}; f{{}}" ENTER - "2 + 2" ENTER), - njs_str("4") }, - - { njs_str("function ff(o) {return o.a.a}" ENTER - "function f(o) {try {return ff(o)} " - "finally {return 1}}" ENTER - "f({})" ENTER), - njs_str("1") }, - - { njs_str("arguments" ENTER - "function(){}()" ENTER), - njs_str("SyntaxError: Unexpected token \"(\" in 1") }, - - /* Backtraces */ - - { njs_str("function ff(o) {return o.a.a}" ENTER - "function f(o) {return ff(o)}" ENTER - "f({})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at ff (:1)\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("function ff(o) {return o.a.a}" ENTER - "function f(o) {try {return ff(o)} " - "finally {return o.a.a}}" ENTER - "f({})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("function f(ff, o) {return ff(o)}" ENTER - "f(function (o) {return o.a.a}, {})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at anonymous (:1)\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("'str'.replace(/t/g," - " function(m) {return m.a.a})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at anonymous (:1)\n" - " at String.prototype.replace (native)\n" - " at main (native)\n") }, - - { njs_str("function f(o) {return Object.keys(o)}" ENTER - "f()" ENTER), - njs_str("TypeError: cannot convert undefined argument to object\n" - " at Object.keys (native)\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("''.repeat(-1)" ENTER), - njs_str("RangeError\n" - " at String.prototype.repeat (native)\n" - " at main (native)\n") }, - - { njs_str("Math.log({}.a.a)" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at Math.log (native)\n" - " at main (native)\n") }, - - { njs_str("var bound = Math.max.bind(null, {toString(){return {}}}); bound(1)" ENTER), - njs_str("TypeError: Cannot convert object to primitive value\n" - " at Math.max (native)\n" - " at main (native)\n") }, - - { njs_str("Object.prototype()" ENTER), - njs_str("TypeError: (intermediate value)[\"prototype\"] is not a function\n" - " at main (native)\n") }, - - { njs_str("eval()" ENTER), - njs_str("InternalError: Not implemented\n" - " at eval (native)\n" - " at main (native)\n") }, - - { njs_str("$r.method({}.a.a)" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at $r3.method (native)\n" - " at main (native)\n") }, - - { njs_str("new Function(\n\n@)" ENTER), - njs_str("SyntaxError: Unexpected token \"@\" in 3") }, - - { njs_str("require()" ENTER), - njs_str("TypeError: missing path\n" - " at require (native)\n" - " at main (native)\n") }, - - { njs_str("setTimeout()" ENTER), - njs_str("TypeError: too few arguments\n" - " at setTimeout (native)\n" - " at main (native)\n") }, - - { njs_str("require('crypto').createHash('sha')" ENTER), - njs_str("TypeError: not supported algorithm: \"sha\"\n" - " at crypto.createHash (native)\n" - " at main (native)\n") }, - - { njs_str("var h = require('crypto').createHash('sha1')" ENTER - "h.update([])" ENTER), - njs_str("TypeError: data must be a string\n" - " at Hash.prototype.update (native)\n" - " at main (native)\n") }, - - { njs_str("require('crypto').createHmac('sha1', [])" ENTER), - njs_str("TypeError: key must be a string\n" - " at crypto.createHmac (native)\n" - " at main (native)\n") }, - - { njs_str("var h = require('crypto').createHmac('sha1', 'secret')" ENTER - "h.update([])" ENTER), - njs_str("TypeError: data must be a string\n" - " at Hmac.prototype.update (native)\n" - " at main (native)\n") }, - - { njs_str("function f(o) {function f_in(o) {return o.a.a};" - " return f_in(o)}; f({})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at f_in (:1)\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("function f(o) {var ff = function (o) {return o.a.a};" - " return ff(o)}; f({})" ENTER), - njs_str("TypeError: cannot get property \"a\" of undefined\n" - " at anonymous (:1)\n" - " at f (:1)\n" - " at main (native)\n") }, - - { njs_str("var fs = require('fs');" - "[" - " 'access'," - " 'accessSync'," - " 'readFile'," - " 'readFileSync'," - " 'writeFile'," - " 'writeFileSync'," - " 'appendFile'," - " 'appendFileSync'," - " 'symlink'," - " 'symlinkSync'," - " 'unlink'," - " 'unlinkSync'," - " 'realpath'," - " 'realpathSync'," - "]" - ".every(v=>{ try {fs[v]();} catch (e) { return e.stack.search(`fs.${v} `) >= 0}})" ENTER), - njs_str("true") }, - - { njs_str("parseInt({ toString: function() { return [1] } })" ENTER), - njs_str("TypeError: Cannot convert object to primitive value\n" - " at parseInt (native)\n" - " at main (native)\n") }, - - { njs_str("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)" ENTER), - njs_str("a") }, - - /* Exception in njs_vm_retval_string() */ - - { njs_str("var o = { toString: function() { return [1] } }" ENTER - "o" ENTER), - njs_str("TypeError: Cannot convert object to primitive value") }, - - /* line numbers */ - - { njs_str("/**/(function(){throw Error();})()" ENTER), - njs_str("Error\n" - " at anonymous (:1)\n" - " at main (native)\n") }, - - { njs_str("/***/(function(){throw Error();})()" ENTER), - njs_str("Error\n" - " at anonymous (:1)\n" - " at main (native)\n") }, - - { njs_str("/*\n**/(function(){throw Error();})()" ENTER), - njs_str("Error\n" - " at anonymous (:2)\n" - " at main (native)\n") }, - -}; - - -static njs_int_t -njs_interactive_test(njs_bool_t verbose) -{ - u_char *start, *last, *end; - njs_vm_t *vm; - njs_int_t ret; - njs_str_t s; - njs_uint_t i; - njs_bool_t success; - njs_vm_opt_t options; - njs_interactive_test_t *test; - - vm = NULL; - ret = NJS_ERROR; - - for (i = 0; i < njs_nitems(njs_test); i++) { - - test = &njs_test[i]; - - if (verbose) { - njs_printf("\"%V\"\n", &test->script); - } - - njs_vm_opt_init(&options); - - options.init = 1; - options.accumulative = 1; - options.backtrace = 1; - - vm = njs_vm_create(&options); - if (vm == NULL) { - njs_printf("njs_vm_create() failed\n"); - goto done; - } - - ret = njs_externals_init(vm, NULL); - if (ret != NJS_OK) { - goto done; - } - - start = test->script.start; - last = start + test->script.length; - end = NULL; - - for ( ;; ) { - start = (end != NULL) ? end + njs_length(ENTER) : start; - if (start >= last) { - break; - } - - end = (u_char *) strstr((char *) start, ENTER); - - ret = njs_vm_compile(vm, &start, end); - if (ret == NJS_OK) { - ret = njs_vm_start(vm); - } - } - - if (njs_vm_retval_string(vm, &s) != NJS_OK) { - njs_printf("njs_vm_retval_string() failed\n"); - goto done; - } - - success = njs_strstr_eq(&test->ret, &s); - if (success) { - njs_vm_destroy(vm); - vm = NULL; - continue; - } - - njs_printf("njs_interactive(\"%V\") failed: \"%V\" vs \"%V\"\n", - &test->script, &test->ret, &s); - - goto done; - } - - ret = NJS_OK; - - njs_printf("njs interactive tests passed\n"); - -done: - - if (vm != NULL) { - njs_vm_destroy(vm); - } - - return ret; -} - - -int njs_cdecl -main(int argc, char **argv) -{ - njs_bool_t verbose; - - verbose = 0; - - if (argc > 1) { - switch (argv[1][0]) { - - case 'v': - verbose = 1; - break; - - default: - break; - } - } - - return njs_interactive_test(verbose); -} diff -r cf85ed422623 -r 6023201cf1f3 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Jun 15 15:26:40 2020 +0000 +++ b/src/test/njs_unit_test.c Mon Jun 15 15:26:44 2020 +0000 @@ -17601,6 +17601,280 @@ static njs_unit_test_t njs_regexp_test[ }; +static njs_unit_test_t njs_shell_test[] = +{ +#define ENTER "\n\3" + + { njs_str("var a = 3" ENTER + "a * 2" ENTER), + njs_str("6") }, + + { njs_str("var a = \"aa\\naa\"" ENTER + "a" ENTER), + njs_str("aa\naa") }, + + { njs_str("var a = 3" ENTER + "var a = 'str'" ENTER + "a" ENTER), + njs_str("str") }, + + { njs_str("var a = 2" ENTER + "a *= 2" ENTER + "a *= 2" ENTER + "a *= 2" ENTER), + njs_str("16") }, + + { njs_str("var a = 2" ENTER + "var b = 3" ENTER + "a * b" ENTER), + njs_str("6") }, + + { njs_str("var a = 2; var b = 3;" ENTER + "a * b" ENTER), + njs_str("6") }, + + { njs_str("function sq(f) { return f() * f() }" ENTER + "sq(function () { return 3 })" ENTER), + njs_str("9") }, + + /* Temporary indexes */ + + { njs_str("var a = [1,2,3], i; for (i in a) {Object.seal({});}" ENTER), + njs_str("undefined") }, + + { njs_str("var i; for (i in [1,2,3]) {Object.seal({});}" ENTER), + njs_str("undefined") }, + + { njs_str("var a = 'A'; " + "switch (a) {" + "case 0: a += '0';" + "case 1: a += '1';" + "}; a" ENTER), + njs_str("A") }, + + { njs_str("var a = 0; try { a = 5 }" + "catch (e) { a = 9 } finally { a++ } a" ENTER), + njs_str("6") }, + + { njs_str("/abc/i.test('ABC')" ENTER), + njs_str("true") }, + + /* Accumulative mode. */ + + { njs_str("var a = 1" ENTER + "a" ENTER), + njs_str("1") }, + + { njs_str("Number.prototype.test = 'test'" ENTER + "Number.prototype.test" ENTER), + njs_str("test") }, + + /* Error handling */ + + { njs_str("var a = ;" ENTER + "2 + 2" ENTER), + njs_str("4") }, + + { njs_str("function f() { return b;" ENTER), + njs_str("SyntaxError: Unexpected end of input in 1") }, + + { njs_str("function f() { return b;" ENTER + "2 + 2" ENTER), + njs_str("4") }, + + { njs_str("function f() { return function() { return 1" ENTER + "2 + 2" ENTER), + njs_str("4") }, + + { njs_str("function f() { return b;}" ENTER + "2 + 2" ENTER), + njs_str("4") }, + + { njs_str("function f(o) { return o.a.a;}; f{{}}" ENTER + "2 + 2" ENTER), + njs_str("4") }, + + { njs_str("function ff(o) {return o.a.a}" ENTER + "function f(o) {try {return ff(o)} " + " finally {return 1}}" ENTER + "f({})" ENTER), + njs_str("1") }, + + { njs_str("arguments" ENTER + "function(){}()" ENTER), + njs_str("SyntaxError: Unexpected token \"(\" in 1") }, + + /* Backtraces */ + + { njs_str("function ff(o) {return o.a.a}" ENTER + "function f(o) {return ff(o)}" ENTER + "f({})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at ff (:1)\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("function ff(o) {return o.a.a}" ENTER + "function f(o) {try {return ff(o)} " + " finally {return o.a.a}}" ENTER + "f({})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("function f(ff, o) {return ff(o)}" ENTER + "f(function (o) {return o.a.a}, {})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at anonymous (:1)\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("'str'.replace(/t/g," + " function(m) {return m.a.a})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at anonymous (:1)\n" + " at String.prototype.replace (native)\n" + " at main (native)\n") }, + + { njs_str("function f(o) {return Object.keys(o)}" ENTER + "f()" ENTER), + njs_str("TypeError: cannot convert undefined argument to object\n" + " at Object.keys (native)\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("''.repeat(-1)" ENTER), + njs_str("RangeError\n" + " at String.prototype.repeat (native)\n" + " at main (native)\n") }, + + { njs_str("Math.log({}.a.a)" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at Math.log (native)\n" + " at main (native)\n") }, + + { njs_str("var bound = Math.max.bind(null, {toString(){return {}}}); bound(1)" ENTER), + njs_str("TypeError: Cannot convert object to primitive value\n" + " at Math.max (native)\n" + " at main (native)\n") }, + + { njs_str("Object.prototype()" ENTER), + njs_str("TypeError: (intermediate value)[\"prototype\"] is not a function\n" + " at main (native)\n") }, + + { njs_str("eval()" ENTER), + njs_str("InternalError: Not implemented\n" + " at eval (native)\n" + " at main (native)\n") }, + + { njs_str("$r.method({}.a.a)" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at $r3.method (native)\n" + " at main (native)\n") }, + + { njs_str("new Function(\n\n@)" ENTER), + njs_str("SyntaxError: Unexpected token \"@\" in 3") }, + + { njs_str("require()" ENTER), + njs_str("TypeError: missing path\n" + " at require (native)\n" + " at main (native)\n") }, + + { njs_str("setTimeout()" ENTER), + njs_str("TypeError: too few arguments\n" + " at setTimeout (native)\n" + " at main (native)\n") }, + + { njs_str("require('crypto').createHash('sha')" ENTER), + njs_str("TypeError: not supported algorithm: \"sha\"\n" + " at crypto.createHash (native)\n" + " at main (native)\n") }, + + { njs_str("var h = require('crypto').createHash('sha1')" ENTER + "h.update([])" ENTER), + njs_str("TypeError: data must be a string\n" + " at Hash.prototype.update (native)\n" + " at main (native)\n") }, + + { njs_str("require('crypto').createHmac('sha1', [])" ENTER), + njs_str("TypeError: key must be a string\n" + " at crypto.createHmac (native)\n" + " at main (native)\n") }, + + { njs_str("var h = require('crypto').createHmac('sha1', 'secret')" ENTER + "h.update([])" ENTER), + njs_str("TypeError: data must be a string\n" + " at Hmac.prototype.update (native)\n" + " at main (native)\n") }, + + { njs_str("function f(o) {function f_in(o) {return o.a.a};" + " return f_in(o)}; f({})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at f_in (:1)\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("function f(o) {var ff = function (o) {return o.a.a};" + " return ff(o)}; f({})" ENTER), + njs_str("TypeError: cannot get property \"a\" of undefined\n" + " at anonymous (:1)\n" + " at f (:1)\n" + " at main (native)\n") }, + + { njs_str("var fs = require('fs');" + "[" + " 'access'," + " 'accessSync'," + " 'readFile'," + " 'readFileSync'," + " 'writeFile'," + " 'writeFileSync'," + " 'appendFile'," + " 'appendFileSync'," + " 'symlink'," + " 'symlinkSync'," + " 'unlink'," + " 'unlinkSync'," + " 'realpath'," + " 'realpathSync'," + "]" + ".every(v=>{ try {fs[v]();} catch (e) { return e.stack.search(`fs.${v} `) >= 0}})" ENTER), + njs_str("true") }, + + { njs_str("parseInt({ toString: function() { return [1] } })" ENTER), + njs_str("TypeError: Cannot convert object to primitive value\n" + " at parseInt (native)\n" + " at main (native)\n") }, + + { njs_str("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)" ENTER), + njs_str("a") }, + + /* Exception in njs_vm_retval_string() */ + + { njs_str("var o = { toString: function() { return [1] } }" ENTER + "o" ENTER), + njs_str("TypeError: Cannot convert object to primitive value") }, + + /* line numbers */ + + { njs_str("/**/(function(){throw Error();})()" ENTER), + njs_str("Error\n" + " at anonymous (:1)\n" + " at main (native)\n") }, + + { njs_str("/***/(function(){throw Error();})()" ENTER), + njs_str("Error\n" + " at anonymous (:1)\n" + " at main (native)\n") }, + + { njs_str("/*\n**/(function(){throw Error();})()" ENTER), + njs_str("Error\n" + " at anonymous (:2)\n" + " at main (native)\n") }, + +}; + + typedef struct { njs_bool_t disassemble; njs_bool_t verbose; @@ -17767,6 +18041,103 @@ done: static njs_int_t +njs_interactive_test(njs_unit_test_t tests[], size_t num, const char *name, + njs_opts_t *opts, njs_stat_t *stat) +{ + u_char *start, *last, *end; + njs_vm_t *vm; + njs_int_t ret; + njs_str_t s; + njs_uint_t i; + njs_stat_t prev; + njs_bool_t success; + njs_vm_opt_t options; + + vm = NULL; + + prev = *stat; + + ret = NJS_ERROR; + + for (i = 0; i < num; i++) { + + if (opts->verbose) { + njs_printf("\"%V\"\n", &tests[i].script); + } + + njs_vm_opt_init(&options); + + options.init = 1; + options.accumulative = 1; + options.backtrace = 1; + + vm = njs_vm_create(&options); + if (vm == NULL) { + njs_printf("njs_vm_create() failed\n"); + goto done; + } + + if (opts->externals) { + ret = njs_externals_init(vm, NULL); + if (ret != NJS_OK) { + goto done; + } + } + + start = tests[i].script.start; + last = start + tests[i].script.length; + end = NULL; + + for ( ;; ) { + start = (end != NULL) ? end + njs_length(ENTER) : start; + if (start >= last) { + break; + } + + end = (u_char *) strstr((char *) start, ENTER); + + ret = njs_vm_compile(vm, &start, end); + if (ret == NJS_OK) { + ret = njs_vm_start(vm); + } + } + + if (njs_vm_retval_string(vm, &s) != NJS_OK) { + njs_printf("njs_vm_retval_string() failed\n"); + goto done; + } + + success = njs_strstr_eq(&tests[i].ret, &s); + + if (!success) { + njs_printf("njs(\"%V\")\nexpected: \"%V\"\n got: \"%V\"\n", + &tests[i].script, &tests[i].ret, &s); + + stat->failed++; + + } else { + stat->passed++; + } + + njs_vm_destroy(vm); + vm = NULL; + } + + ret = NJS_OK; + +done: + + if (vm != NULL) { + njs_vm_destroy(vm); + } + + njs_unit_test_report(name, &prev, stat); + + return ret; +} + + +static njs_int_t njs_timezone_optional_test(njs_opts_t *opts, njs_stat_t *stat) { size_t size; @@ -18794,6 +19165,12 @@ main(int argc, char **argv) return ret; } + ret = njs_interactive_test(njs_shell_test, njs_nitems(njs_shell_test), + "interactive tests", &opts, &stat); + if (ret != NJS_OK) { + return ret; + } + opts.repeat = 128; ret = njs_unit_test(njs_shared_test, njs_nitems(njs_shared_test), From alexander.borisov at nginx.com Mon Jun 15 15:34:54 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Mon, 15 Jun 2020 15:34:54 +0000 Subject: [njs] Parser: fixed semicolon check after continue/break statement. Message-ID: details: https://hg.nginx.org/njs/rev/3bfa26b91a55 branches: changeset: 1432:3bfa26b91a55 user: Alexander Borisov date: Mon Jun 15 18:33:57 2020 +0300 description: Parser: fixed semicolon check after continue/break statement. This closes #318 issue on GitHub. diffstat: src/njs_parser.c | 10 ++++------ src/test/njs_unit_test.c | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diffs (44 lines): diff -r 6023201cf1f3 -r 3bfa26b91a55 src/njs_parser.c --- a/src/njs_parser.c Mon Jun 15 15:26:44 2020 +0000 +++ b/src/njs_parser.c Mon Jun 15 18:33:57 2020 +0300 @@ -5645,13 +5645,11 @@ njs_parser_break_continue(njs_parser_t * return njs_parser_failed(parser); default: - if (!parser->strict_semicolon - && parser->lexer->prev_type == NJS_TOKEN_LINE_END) - { - break; - } - if (njs_lexer_token_is_label_identifier(token)) { + if (parser->lexer->prev_type == NJS_TOKEN_LINE_END) { + return njs_parser_stack_pop(parser); + } + if (njs_label_find(parser->vm, parser->scope, token->unique_id) == NULL) { diff -r 6023201cf1f3 -r 3bfa26b91a55 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Mon Jun 15 15:26:44 2020 +0000 +++ b/src/test/njs_unit_test.c Mon Jun 15 18:33:57 2020 +0300 @@ -2828,6 +2828,9 @@ static njs_unit_test_t njs_test[] = { njs_str("var i; for (i in [1,2,3]) {Object.seal({});}"), njs_str("undefined") }, + { njs_str("while (0) {continue\n}"), + njs_str("undefined") }, + /* break. */ { njs_str("break"), @@ -2896,6 +2899,9 @@ static njs_unit_test_t njs_test[] = "for (i in a) if (a[i] > 4) break; s += a[i]; s"), njs_str("5") }, + { njs_str("while (0) {break\n}"), + njs_str("undefined") }, + /* Labels. */ { njs_str("var n = 0; a:{n++}; a:{n++}; n"), From rnickb731 at gmail.com Mon Jun 15 17:52:20 2020 From: rnickb731 at gmail.com (Ryan Burn) Date: Mon, 15 Jun 2020 10:52:20 -0700 Subject: Any way for a module to set directives when it's loaded? Message-ID: Suppose I'm writing an nginx module foo. Is there any way to have foo set default directives when it gets loaded? For example, if I wanted foo to add headers to every request could I have load_module modules/ngx_http_foo_module.so; implicitly add proxy_set_header foo-header bar-value; ... to the http context? From quantum2048 at gmail.com Mon Jun 15 22:16:32 2020 From: quantum2048 at gmail.com (Quantum) Date: Mon, 15 Jun 2020 18:16:32 -0400 Subject: [PATCH] Correctly flush request body to uwsgi with SSL Message-ID: # HG changeset patch # User Quantum # Date 1592256926 14400 # Mon Jun 15 17:35:26 2020 -0400 # Node ID eff63a5758aaca39545fd81bb646194987ae0ee3 # Parent d127837c714f398e04cc8cf26f922c845fb7a6e8 Correctly flush request body to uwsgi with SSL The flush flag was not set when forwarding the request body to the uwsgi server. When using uwsgi_pass suwsgi://..., this causes the uwsgi server to wait indefinitely for the request body and eventually time out due to SSL buffering. This is essentially the same change as 4009:3183165283cc, which was made to ngx_http_proxy_module.c. This will fix the uwsgi bug https://github.com/unbit/uwsgi/issues/1490. diff -r d127837c714f -r eff63a5758aa src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 08 11:40:34 2020 +0300 +++ b/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 15 17:35:26 2020 -0400 @@ -1141,6 +1141,7 @@ r->upstream->request_bufs = cl; } + b->flush = 1; cl->next = NULL; return NGX_OK; From pluknet at nginx.com Mon Jun 15 23:57:46 2020 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 16 Jun 2020 02:57:46 +0300 Subject: nginx-quic & reload In-Reply-To: <97f2f1c1e24b40ff403148a5cc654ebfc5e8ce70.camel@gmail.com> References: <97f2f1c1e24b40ff403148a5cc654ebfc5e8ce70.camel@gmail.com> Message-ID: > On 12 Jun 2020, at 12:41, Jan Pracha? wrote: > > Hello, I checked code at the nginx-quic repo and I can't see how the > following problem is addressed. > > When nginx reloads config, new workers are created and they inhertis > receiving sockets from the old workers. That means that the new workers > will start processing packets of the quic connections of the old > workers. But the new workers lack context for them, so they will ignore > the packets and quic connection will timeout, right? Correct. > A similar problem exists when a binary is changed. > > Do I miss something or will it be solved in the future? This could be handled by a combination of CONNECTION_CLOSE in old workers and Stateless Reset in new workers. -- Sergey Kandaurov From mdounin at mdounin.ru Tue Jun 16 12:58:29 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Jun 2020 15:58:29 +0300 Subject: Any way for a module to set directives when it's loaded? In-Reply-To: References: Message-ID: <20200616125829.GU12747@mdounin.ru> Hello! On Mon, Jun 15, 2020 at 10:52:20AM -0700, Ryan Burn wrote: > Suppose I'm writing an nginx module foo. Is there any way to have foo > set default directives when it gets loaded? > > For example, if I wanted foo to add headers to every request could I have > > load_module modules/ngx_http_foo_module.so; > > implicitly add > > proxy_set_header foo-header bar-value; > ... > > to the http context? No, this is not something possible. Consider instructing your module users to add relevant proxy_set_header directives to the configuration instead. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Tue Jun 16 18:26:51 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Jun 2020 18:26:51 +0000 Subject: [nginx] Correctly flush request body to uwsgi with SSL. Message-ID: details: https://hg.nginx.org/nginx/rev/8cf31489b479 branches: changeset: 7666:8cf31489b479 user: Quantum date: Mon Jun 15 17:35:26 2020 -0400 description: Correctly flush request body to uwsgi with SSL. The flush flag was not set when forwarding the request body to the uwsgi server. When using uwsgi_pass suwsgi://..., this causes the uwsgi server to wait indefinitely for the request body and eventually time out due to SSL buffering. This is essentially the same change as 4009:3183165283cc, which was made to ngx_http_proxy_module.c. This will fix the uwsgi bug https://github.com/unbit/uwsgi/issues/1490. diffstat: src/http/modules/ngx_http_uwsgi_module.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r d127837c714f -r 8cf31489b479 src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 08 11:40:34 2020 +0300 +++ b/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 15 17:35:26 2020 -0400 @@ -1141,6 +1141,7 @@ ngx_http_uwsgi_create_request(ngx_http_r r->upstream->request_bufs = cl; } + b->flush = 1; cl->next = NULL; return NGX_OK; From mdounin at mdounin.ru Tue Jun 16 18:28:08 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 16 Jun 2020 21:28:08 +0300 Subject: [PATCH] Correctly flush request body to uwsgi with SSL In-Reply-To: References: Message-ID: <20200616182808.GW12747@mdounin.ru> Hello! On Mon, Jun 15, 2020 at 06:16:32PM -0400, Quantum wrote: > # HG changeset patch > # User Quantum > # Date 1592256926 14400 > # Mon Jun 15 17:35:26 2020 -0400 > # Node ID eff63a5758aaca39545fd81bb646194987ae0ee3 > # Parent d127837c714f398e04cc8cf26f922c845fb7a6e8 > Correctly flush request body to uwsgi with SSL > > The flush flag was not set when forwarding the request body to the uwsgi > server. When using uwsgi_pass suwsgi://..., this causes the uwsgi server > to wait indefinitely for the request body and eventually time out due to > SSL buffering. > > This is essentially the same change as 4009:3183165283cc, which was made > to ngx_http_proxy_module.c. > > This will fix the uwsgi bug https://github.com/unbit/uwsgi/issues/1490. > > diff -r d127837c714f -r eff63a5758aa src/http/modules/ngx_http_uwsgi_module.c > --- a/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 08 11:40:34 2020 +0300 > +++ b/src/http/modules/ngx_http_uwsgi_module.c Mon Jun 15 17:35:26 2020 -0400 > @@ -1141,6 +1141,7 @@ > r->upstream->request_bufs = cl; > } > > + b->flush = 1; > cl->next = NULL; > > return NGX_OK; Thanks for the patch. Rather, it looks like a combination of 4009:3183165283cc and a much earlier fix from 611:3f8a2132b93d (nginx 0.3.7). The 4009:3183165283cc change itself is about exotic modes like "proxy_pass_request_body off;" or "proxy_set_body ;", while the most common case was fixed in 611:3f8a2132b93d. Committed. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Wed Jun 17 14:40:09 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 17 Jun 2020 14:40:09 +0000 Subject: [njs] Optimizing njs_native_frame_t structure. Message-ID: details: https://hg.nginx.org/njs/rev/d37766e94c82 branches: changeset: 1433:d37766e94c82 user: Dmitry Volyntsev date: Tue Jun 16 13:55:25 2020 +0000 description: Optimizing njs_native_frame_t structure. Moving njs_exception_t from njs_native_frame_t to njs_frame_t, as the exception structure is only needed for lambda frames. diffstat: src/njs_function.c | 4 ++++ src/njs_function.h | 26 ++++++++++++-------------- src/njs_vmcode.c | 50 +++++++++++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 35 deletions(-) diffs (210 lines): diff -r 3bfa26b91a55 -r d37766e94c82 src/njs_function.c --- a/src/njs_function.c Mon Jun 15 18:33:57 2020 +0300 +++ b/src/njs_function.c Tue Jun 16 13:55:25 2020 +0000 @@ -370,6 +370,7 @@ njs_function_native_frame(njs_vm_t *vm, frame->function = function; frame->nargs = function->args_offset + nargs; frame->ctor = ctor; + frame->native = 1; value = (njs_value_t *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE); frame->arguments = value; @@ -452,6 +453,7 @@ njs_function_lambda_frame(njs_vm_t *vm, native_frame->function = target; native_frame->nargs = nargs; native_frame->ctor = ctor; + native_frame->native = 0; /* Function arguments. */ @@ -501,6 +503,8 @@ njs_function_lambda_frame(njs_vm_t *vm, } frame = (njs_frame_t *) native_frame; + frame->exception.catch = NULL; + frame->exception.next = NULL; frame->local = value; frame->previous_active_frame = vm->active_frame; diff -r 3bfa26b91a55 -r d37766e94c82 src/njs_function.h --- a/src/njs_function.h Mon Jun 15 18:33:57 2020 +0300 +++ b/src/njs_function.h Tue Jun 16 13:55:25 2020 +0000 @@ -42,18 +42,6 @@ struct njs_function_lambda_s { #define NJS_FRAME_SPARE_SIZE 512 -typedef struct njs_exception_s njs_exception_t; - -struct njs_exception_s { - /* - * The next field must be the first to alias it with restart address - * because it is not used to detect catch block existance in the frame. - */ - njs_exception_t *next; - u_char *catch; -}; - - struct njs_native_frame_s { u_char *free; @@ -63,13 +51,13 @@ struct njs_native_frame_s { njs_value_t *arguments; njs_object_t *arguments_object; - njs_exception_t exception; njs_index_t retval; uint32_t size; uint32_t free_size; uint32_t nargs; + uint8_t native; /* 1 bit */ /* Function is called as constructor with "new" keyword. */ uint8_t ctor; /* 1 bit */ @@ -78,9 +66,19 @@ struct njs_native_frame_s { }; +typedef struct njs_exception_s njs_exception_t; + +struct njs_exception_s { + njs_exception_t *next; + u_char *catch; +}; + + struct njs_frame_s { njs_native_frame_t native; + njs_exception_t exception; + njs_frame_t *previous_active_frame; njs_value_t *local; @@ -169,7 +167,7 @@ njs_function_frame_invoke(njs_vm_t *vm, frame = vm->top_frame; frame->retval = retval; - if (frame->function->native) { + if (frame->native) { return njs_function_native_call(vm); } else { diff -r 3bfa26b91a55 -r d37766e94c82 src/njs_vmcode.c --- a/src/njs_vmcode.c Mon Jun 15 18:33:57 2020 +0300 +++ b/src/njs_vmcode.c Tue Jun 16 13:55:25 2020 +0000 @@ -90,7 +90,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c njs_frame_t *frame; njs_jump_off_t ret; njs_vmcode_this_t *this; - njs_native_frame_t *previous; + njs_native_frame_t *previous, *native; njs_property_next_t *next; njs_vmcode_generic_t *vmcode; njs_vmcode_prop_get_t *get; @@ -867,8 +867,8 @@ next: ret = njs_vmcode_try_end(vm, value1, value2); } else { - vm->top_frame->exception.catch = - pc + (njs_jump_off_t) value2; + frame = (njs_frame_t *) vm->top_frame; + frame->exception.catch = pc + (njs_jump_off_t) value2; ret = sizeof(njs_vmcode_catch_t); } @@ -906,28 +906,31 @@ error: } for ( ;; ) { - frame = (njs_frame_t *) vm->top_frame; + native = vm->top_frame; - catch = frame->native.exception.catch; + if (!native->native) { + frame = (njs_frame_t *) native; + catch = frame->exception.catch; - if (catch != NULL) { - pc = catch; + if (catch != NULL) { + pc = catch; - goto next; + goto next; + } } - previous = frame->native.previous; + previous = native->previous; if (previous == NULL) { break; } - lambda_call = (frame == vm->active_frame); + lambda_call = (native == &vm->active_frame->native); - njs_vm_scopes_restore(vm, &frame->native, previous); + njs_vm_scopes_restore(vm, native, previous); - if (frame->native.size != 0) { - vm->stack_size -= frame->native.size; - njs_mp_free(vm->mem_pool, frame); + if (native->size != 0) { + vm->stack_size -= native->size; + njs_mp_free(vm->mem_pool, native); } if (lambda_call) { @@ -1715,21 +1718,24 @@ njs_vmcode_try_start(njs_vm_t *vm, njs_v njs_value_t *offset, u_char *pc) { njs_value_t *exit_value; + njs_frame_t *frame; njs_exception_t *e; njs_vmcode_try_start_t *try_start; - if (vm->top_frame->exception.catch != NULL) { + frame = (njs_frame_t *) vm->top_frame; + + if (frame->exception.catch != NULL) { e = njs_mp_alloc(vm->mem_pool, sizeof(njs_exception_t)); if (njs_slow_path(e == NULL)) { njs_memory_error(vm); return NJS_ERROR; } - *e = vm->top_frame->exception; - vm->top_frame->exception.next = e; + *e = frame->exception; + frame->exception.next = e; } - vm->top_frame->exception.catch = pc + (njs_jump_off_t) offset; + frame->exception.catch = pc + (njs_jump_off_t) offset; njs_set_invalid(exception_value); @@ -1784,15 +1790,17 @@ njs_vmcode_try_continue(njs_vm_t *vm, nj static njs_jump_off_t njs_vmcode_try_end(njs_vm_t *vm, njs_value_t *invld, njs_value_t *offset) { + njs_frame_t *frame; njs_exception_t *e; - e = vm->top_frame->exception.next; + frame = (njs_frame_t *) vm->top_frame; + e = frame->exception.next; if (e == NULL) { - vm->top_frame->exception.catch = NULL; + frame->exception.catch = NULL; } else { - vm->top_frame->exception = *e; + frame->exception = *e; njs_mp_free(vm->mem_pool, e); } From xeioex at nginx.com Wed Jun 17 14:40:11 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 17 Jun 2020 14:40:11 +0000 Subject: [njs] Improved unit test. Message-ID: details: https://hg.nginx.org/njs/rev/02634f76f6d0 branches: changeset: 1434:02634f76f6d0 user: Dmitry Volyntsev date: Wed Jun 17 14:38:23 2020 +0000 description: Improved unit test. 1) Accepting multiple options. 2) Added filter option, to run only selected suites. For example, the following command would run only selected tests: $ njs_unit_test -f "module|externals" module tests: PASSED [5/5] externals tests: PASSED [76/76] TOTAL: PASSED [81/81] diffstat: src/test/njs_unit_test.c | 395 +++++++++++++++++++++++++++++++--------------- 1 files changed, 268 insertions(+), 127 deletions(-) diffs (536 lines): diff -r d37766e94c82 -r 02634f76f6d0 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 16 13:55:25 2020 +0000 +++ b/src/test/njs_unit_test.c Wed Jun 17 14:38:23 2020 +0000 @@ -17883,11 +17883,13 @@ static njs_unit_test_t njs_shell_test[] typedef struct { njs_bool_t disassemble; + njs_str_t filter; njs_bool_t verbose; - njs_bool_t unsafe; + + njs_uint_t externals; njs_bool_t module; njs_uint_t repeat; - njs_uint_t externals; + njs_bool_t unsafe; } njs_opts_t; @@ -17898,20 +17900,21 @@ typedef struct { static void -njs_unit_test_report(const char *msg, njs_stat_t *prev, njs_stat_t *current) +njs_unit_test_report(njs_str_t *name, njs_stat_t *prev, njs_stat_t *current) { njs_stat_t stat; stat.failed = current->failed - prev->failed; stat.passed = current->passed - prev->passed; - njs_printf("%s: %s [%d/%d]\n", msg, stat.failed ? "FAILED" : "PASSED", - stat.passed, stat.passed + stat.failed); + njs_printf("%V tests: %s [%d/%d]\n", name, + stat.failed ? "FAILED" : "PASSED", stat.passed, + stat.passed + stat.failed); } static njs_int_t -njs_unit_test(njs_unit_test_t tests[], size_t num, const char *name, +njs_unit_test(njs_unit_test_t tests[], size_t num, njs_str_t *name, njs_opts_t *opts, njs_stat_t *stat) { u_char *start, *end; @@ -18047,7 +18050,7 @@ done: static njs_int_t -njs_interactive_test(njs_unit_test_t tests[], size_t num, const char *name, +njs_interactive_test(njs_unit_test_t tests[], size_t num, njs_str_t *name, njs_opts_t *opts, njs_stat_t *stat) { u_char *start, *last, *end; @@ -18091,7 +18094,7 @@ njs_interactive_test(njs_unit_test_t tes } start = tests[i].script.start; - last = start + tests[i].script.length; + last = start + tests[i].script.length; end = NULL; for ( ;; ) { @@ -18104,6 +18107,10 @@ njs_interactive_test(njs_unit_test_t tes ret = njs_vm_compile(vm, &start, end); if (ret == NJS_OK) { + if (opts->disassemble) { + njs_disassembler(vm); + } + ret = njs_vm_start(vm); } } @@ -18144,7 +18151,8 @@ done: static njs_int_t -njs_timezone_optional_test(njs_opts_t *opts, njs_stat_t *stat) +njs_timezone_optional_test(njs_unit_test_t tests[], size_t num, njs_str_t *name, + njs_opts_t *opts, njs_stat_t *stat) { size_t size; u_char buf[16]; @@ -18165,8 +18173,7 @@ njs_timezone_optional_test(njs_opts_t *o size = strftime((char *) buf, sizeof(buf), "%z", &tm); if (memcmp(buf, "+1245", size) == 0) { - ret = njs_unit_test(njs_tz_test, njs_nitems(njs_tz_test), - "timezone tests", opts, stat); + ret = njs_unit_test(tests, num, name, opts, stat); if (ret != NJS_OK) { return ret; } @@ -18180,7 +18187,8 @@ njs_timezone_optional_test(njs_opts_t *o static njs_int_t -njs_regexp_optional_test(njs_opts_t *opts, njs_stat_t *stat) +njs_regexp_optional_test(njs_unit_test_t tests[], size_t num, njs_str_t *name, + njs_opts_t *opts, njs_stat_t *stat) { int erroff; pcre *re1, *re2; @@ -18205,8 +18213,7 @@ njs_regexp_optional_test(njs_opts_t *opt &errstr, &erroff, NULL); if (re1 == NULL && re2 != NULL) { - ret = njs_unit_test(njs_regexp_test, njs_nitems(njs_regexp_test), - "unicode regexp tests", opts, stat); + ret = njs_unit_test(tests, num, name, opts, stat); if (ret != NJS_OK) { return ret; } @@ -18228,7 +18235,8 @@ njs_regexp_optional_test(njs_opts_t *opt static njs_int_t -njs_vm_json_test(njs_opts_t *opts, njs_stat_t *stat) +njs_vm_json_test(njs_unit_test_t unused[], size_t num, njs_str_t *name, + njs_opts_t *opts, njs_stat_t *stat) { njs_vm_t *vm; njs_int_t ret; @@ -18346,7 +18354,7 @@ done: } } - njs_unit_test_report("VM json API tests", &prev, stat); + njs_unit_test_report(name, &prev, stat); if (vm != NULL) { njs_vm_destroy(vm); @@ -18357,7 +18365,8 @@ done: static njs_int_t -njs_vm_value_test(njs_opts_t *opts, njs_stat_t *stat) +njs_vm_value_test(njs_unit_test_t unused[], size_t num, njs_str_t *name, + njs_opts_t *opts, njs_stat_t *stat) { njs_vm_t *vm; njs_int_t ret; @@ -18501,7 +18510,7 @@ done: } } - njs_unit_test_report("njs_vm_value() tests", &prev, stat); + njs_unit_test_report(name, &prev, stat); if (vm != NULL) { njs_vm_destroy(vm); @@ -18999,7 +19008,8 @@ njs_string_to_index_test(njs_vm_t *vm, n static njs_int_t -njs_api_test(njs_opts_t *opts, njs_stat_t *stat) +njs_vm_internal_api_test(njs_unit_test_t unused[], size_t num, njs_str_t *name, + njs_opts_t *opts, njs_stat_t *stat) { njs_vm_t *vm; njs_int_t ret; @@ -19053,7 +19063,7 @@ njs_api_test(njs_opts_t *opts, njs_stat_ done: - njs_unit_test_report("API tests", &prev, stat); + njs_unit_test_report(name, &prev, stat); if (vm != NULL) { njs_vm_destroy(vm); @@ -19063,126 +19073,257 @@ done: } +static njs_int_t +njs_get_options(njs_opts_t *opts, int argc, char **argv) +{ + char *p; + njs_int_t i; + + static const char help[] = + "njs unit tests.\n" + "\n" + "njs_unit_test [options]" + "\n" + "Options:\n" + " -d print disassembled code.\n" + " -f PATTERN1[|PATTERN2..] filter test suites to run.\n" + " -v verbose mode.\n"; + + for (i = 1; i < argc; i++) { + + p = argv[i]; + + if (p[0] != '-') { + goto help; + } + + p++; + + switch (*p) { + case '?': + case 'h': + (void) write(STDOUT_FILENO, help, njs_length(help)); + return NJS_DONE; + + case 'd': + opts->disassemble = 1; + break; + + case 'f': + if (++i < argc) { + opts->filter.start = (u_char *) argv[i]; + opts->filter.length = njs_strlen(argv[i]); + break; + } + + njs_stderror("option \"-f\" requires argument\n"); + return NJS_ERROR; + + case 'v': + opts->verbose = 1; + break; + + default: + goto help; + } + } + + return NJS_OK; + +help: + + njs_stderror("Unknown argument: \"%s\" " + "try \"%s -h\" for available options\n", argv[i], + argv[0]); + + return NJS_ERROR; +} + + +static njs_int_t +njs_match_test(njs_opts_t *opts, njs_str_t *name) +{ + u_char *p, *start, *end; + size_t len; + + if (name->length == 0) { + return 0; + } + + if (opts->filter.length == 0) { + return 1; + } + + start = opts->filter.start; + end = start + opts->filter.length; + + for ( ;; ) { + p = njs_strlchr(start, end, '|'); + len = ((p != NULL) ? p : end) - start; + len = njs_min(name->length, len); + + if (len != 0 && njs_strncmp(name->start, start, len) == 0) { + return 1; + } + + if (p == NULL) { + break; + } + + start = p + 1; + } + + return 0; +} + + +typedef struct { + njs_str_t name; + njs_opts_t opts; + njs_unit_test_t *tests; + size_t n; + njs_int_t (*run)(njs_unit_test_t tests[], size_t num, + njs_str_t *name, njs_opts_t *opts, + njs_stat_t *stat); +} njs_test_suite_t; + + +static njs_int_t +njs_disabled_denormals_tests(njs_unit_test_t tests[], size_t num, + njs_str_t *name, njs_opts_t *opts, njs_stat_t *stat) +{ + njs_int_t ret; + + njs_mm_denormals(0); + + ret = njs_unit_test(tests, num, name, opts, stat); + + njs_mm_denormals(1); + + return ret; +} + + +static njs_test_suite_t njs_suites[] = +{ + { njs_str("script"), + { .repeat = 1, .unsafe = 1 }, + njs_test, + njs_nitems(njs_test), + njs_unit_test }, + + { njs_str("denormals"), + { .repeat = 1, .unsafe = 1 }, + njs_denormals_test, + njs_nitems(njs_denormals_test), + njs_unit_test }, + + { +#if (NJS_HAVE_DENORMALS_CONTROL) + njs_str("disabled denormals"), +#else + njs_str(""), +#endif + { .repeat = 1, .unsafe = 1 }, + njs_disabled_denormals_test, + njs_nitems(njs_disabled_denormals_test), + njs_disabled_denormals_tests }, + + { njs_str("module"), + { .repeat = 1, .module = 1, .unsafe = 1 }, + njs_module_test, + njs_nitems(njs_module_test), + njs_unit_test }, + + { njs_str("externals"), + { .externals = 1, .repeat = 1, .unsafe = 1 }, + njs_externals_test, + njs_nitems(njs_externals_test), + njs_unit_test }, + + { njs_str("shared"), + { .externals = 1, .repeat = 128, .unsafe = 1 }, + njs_shared_test, + njs_nitems(njs_shared_test), + njs_unit_test }, + + { njs_str("interactive"), + { .externals = 1, .repeat = 1, .unsafe = 1 }, + njs_shell_test, + njs_nitems(njs_shell_test), + njs_interactive_test }, + + { njs_str("timezone"), + { .repeat = 1, .unsafe = 1 }, + njs_tz_test, + njs_nitems(njs_tz_test), + njs_timezone_optional_test }, + + { njs_str("regexp"), + { .repeat = 1, .unsafe = 1 }, + njs_regexp_test, + njs_nitems(njs_regexp_test), + njs_regexp_optional_test }, + + { njs_str("vm_json"), + { .repeat = 1, .unsafe = 1 }, + NULL, + 0, + njs_vm_json_test }, + + { njs_str("vm_value"), + { .repeat = 1, .unsafe = 1 }, + NULL, + 0, + njs_vm_value_test }, + + { njs_str("vm_internal_api"), + { .repeat = 1, .unsafe = 1 }, + NULL, + 0, + njs_vm_internal_api_test }, +}; + + int njs_cdecl main(int argc, char **argv) { - njs_int_t ret; - njs_opts_t opts; - njs_stat_t stat; + njs_int_t ret; + njs_uint_t i; + njs_opts_t opts, op; + njs_stat_t stat; + njs_test_suite_t *suite; njs_memzero(&opts, sizeof(njs_opts_t)); - if (argc > 1) { - switch (argv[1][0]) { - - case 'd': - opts.disassemble = 1; - break; - - case 'v': - opts.verbose = 1; - break; - - default: - break; - } + ret = njs_get_options(&opts, argc, argv); + if (ret != NJS_OK) { + return (ret == NJS_DONE) ? EXIT_SUCCESS: EXIT_FAILURE; } (void) putenv((char *) "TZ=UTC"); tzset(); + njs_mm_denormals(1); + njs_memzero(&stat, sizeof(njs_stat_t)); - opts.repeat = 1; - opts.unsafe = 1; - - njs_mm_denormals(1); - - ret = njs_unit_test(njs_test, njs_nitems(njs_test), "script tests", - &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_unit_test(njs_denormals_test, njs_nitems(njs_denormals_test), - "denormals tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - -#if (NJS_HAVE_DENORMALS_CONTROL) - - njs_mm_denormals(0); - - ret = njs_unit_test(njs_disabled_denormals_test, - njs_nitems(njs_disabled_denormals_test), - "disabled denormals tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - njs_mm_denormals(1); - -#else - - (void) njs_disabled_denormals_test; - -#endif - - ret = njs_timezone_optional_test(&opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_regexp_optional_test(&opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_vm_json_test(&opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_vm_value_test(&opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_api_test(&opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - opts.module = 1; - - ret = njs_unit_test(njs_module_test, njs_nitems(njs_module_test), - "module tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - opts.module = 0; - opts.externals = 1; - - ret = njs_unit_test(njs_externals_test, njs_nitems(njs_externals_test), - "externals tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - ret = njs_interactive_test(njs_shell_test, njs_nitems(njs_shell_test), - "interactive tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; - } - - opts.repeat = 128; - - ret = njs_unit_test(njs_shared_test, njs_nitems(njs_shared_test), - "shared tests", &opts, &stat); - if (ret != NJS_OK) { - return ret; + for (i = 0; i < njs_nitems(njs_suites); i++) { + suite = &njs_suites[i]; + + if (!njs_match_test(&opts, &suite->name)) { + continue; + } + + op = suite->opts; + + op.verbose = opts.verbose; + op.disassemble = opts.disassemble; + + ret = suite->run(suite->tests, suite->n, &suite->name, &op, &stat); + if (ret != NJS_OK) { + return ret; + } } njs_printf("TOTAL: %s [%ui/%ui]\n", stat.failed ? "FAILED" : "PASSED", From thibaultcha at fastmail.com Thu Jun 18 01:55:36 2020 From: thibaultcha at fastmail.com (Thibault Charbonnier) Date: Wed, 17 Jun 2020 18:55:36 -0700 Subject: Fixed use-of-uninitialized-value inside ngx_epoll_test_rdhup. Message-ID: <4d5a6b6c-7d02-4d33-b9a0-aa99021dde98@www.fastmail.com> # HG changeset patch # User Thibault Charbonnier # Date 1592445047 25200 # Wed Jun 17 18:50:47 2020 -0700 # Node ID 3b1e0c7867c40fc82455b5c5dbf1d2e1521c1c8b # Parent 8cf31489b479b689b7ff4a9601ce24c914d0394c Fixed use-of-uninitialized-value inside ngx_epoll_test_rdhup. An issue detected by Valgrind. diff -r 8cf31489b479 -r 3b1e0c7867c4 src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c Mon Jun 15 17:35:26 2020 -0400 +++ b/src/event/modules/ngx_epoll_module.c Wed Jun 17 18:50:47 2020 -0700 @@ -473,6 +473,8 @@ return; } + ngx_memzero(&ee, sizeof(struct epoll_event)); + ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP; if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) { -------------- next part -------------- A non-text attachment was scrubbed... Name: nginx.patch Type: text/x-patch Size: 755 bytes Desc: not available URL: From mdounin at mdounin.ru Thu Jun 18 14:43:35 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 18 Jun 2020 17:43:35 +0300 Subject: Fixed use-of-uninitialized-value inside ngx_epoll_test_rdhup. In-Reply-To: <4d5a6b6c-7d02-4d33-b9a0-aa99021dde98@www.fastmail.com> References: <4d5a6b6c-7d02-4d33-b9a0-aa99021dde98@www.fastmail.com> Message-ID: <20200618144335.GZ12747@mdounin.ru> Hello! On Wed, Jun 17, 2020 at 06:55:36PM -0700, Thibault Charbonnier wrote: > # HG changeset patch > # User Thibault Charbonnier > # Date 1592445047 25200 > # Wed Jun 17 18:50:47 2020 -0700 > # Node ID 3b1e0c7867c40fc82455b5c5dbf1d2e1521c1c8b > # Parent 8cf31489b479b689b7ff4a9601ce24c914d0394c > Fixed use-of-uninitialized-value inside ngx_epoll_test_rdhup. > > An issue detected by Valgrind. > > diff -r 8cf31489b479 -r 3b1e0c7867c4 src/event/modules/ngx_epoll_module.c > --- a/src/event/modules/ngx_epoll_module.c Mon Jun 15 17:35:26 2020 -0400 > +++ b/src/event/modules/ngx_epoll_module.c Wed Jun 17 18:50:47 2020 -0700 > @@ -473,6 +473,8 @@ > return; > } > > + ngx_memzero(&ee, sizeof(struct epoll_event)); > + > ee.events = EPOLLET|EPOLLIN|EPOLLRDHUP; > > if (epoll_ctl(ep, EPOLL_CTL_ADD, s[0], &ee) == -1) { What makes you think that there is a use of uninitialized value here? Note that Valgrind tends to complain about "use of ..." for each and every bit of uninitialized data passed to the kernel, even if the data is not used. While there are no objections to adding ngx_memzero() to silence these Valgrind complaints, these changes are to be documented as fixing Valgrid complaints, not real problems, see 5245:711fa02afae8 and 5252:982678c5c270 for examples. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Thu Jun 18 18:56:34 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Jun 2020 18:56:34 +0000 Subject: [njs] Introduced line level backtrace. Message-ID: details: https://hg.nginx.org/njs/rev/ea2ec4c3ed7d branches: changeset: 1435:ea2ec4c3ed7d user: Dmitry Volyntsev date: Thu Jun 18 18:56:24 2020 +0000 description: Introduced line level backtrace. This closes #140 issue on Github. diffstat: src/njs.h | 1 - src/njs_disassembler.c | 119 +++++++------ src/njs_error.c | 135 ++++++++++++++++- src/njs_function.c | 17 +- src/njs_function.h | 1 + src/njs_generator.c | 383 ++++++++++++++++++++++++++-------------------- src/njs_generator.h | 5 +- src/njs_vm.c | 151 +----------------- src/njs_vm.h | 32 +-- src/njs_vmcode.c | 5 +- src/test/njs_unit_test.c | 72 +++++-- test/njs_expect_test.exp | 16 +- 12 files changed, 503 insertions(+), 434 deletions(-) diffs (truncated from 2138 to 1000 lines): diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs.h --- a/src/njs.h Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs.h Thu Jun 18 18:56:24 2020 +0000 @@ -293,7 +293,6 @@ NJS_EXPORT njs_function_t *njs_vm_functi njs_function_native_t native); NJS_EXPORT void njs_disassembler(njs_vm_t *vm); -NJS_EXPORT void njs_disassemble(u_char *start, u_char *end); NJS_EXPORT njs_int_t njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name, const njs_value_t *value, njs_bool_t shared); diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_disassembler.c --- a/src/njs_disassembler.c Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs_disassembler.c Thu Jun 18 18:56:24 2020 +0000 @@ -15,6 +15,9 @@ typedef struct { } njs_code_name_t; +static void njs_disassemble(njs_vm_code_t *code); + + static njs_code_name_t code_names[] = { { NJS_VMCODE_OBJECT, sizeof(njs_vmcode_object_t), @@ -143,11 +146,12 @@ njs_disassembler(njs_vm_t *vm) njs_vm_code_t *code; code = vm->codes->start; - n = vm->codes->items; + code += vm->main_index; + n = vm->codes->items - vm->main_index; while (n != 0) { njs_printf("%V:%V\n", &code->file, &code->name); - njs_disassemble(code->start, code->end); + njs_disassemble(code); code++; n--; } @@ -156,10 +160,11 @@ njs_disassembler(njs_vm_t *vm) } -void -njs_disassemble(u_char *start, u_char *end) +static void +njs_disassemble(njs_vm_code_t *code) { - u_char *p; + u_char *p, *start, *end; + uint32_t line; njs_str_t *name; njs_uint_t n; njs_code_name_t *code_name; @@ -184,7 +189,8 @@ njs_disassemble(u_char *start, u_char *e njs_vmcode_try_trampoline_t *try_tramp; njs_vmcode_function_frame_t *function; - p = start; + start = code->start; + end = code->end; /* * On some 32-bit platform uintptr_t is int and compilers warn @@ -192,14 +198,17 @@ njs_disassemble(u_char *start, u_char *e * there is no run-time overhead. */ + p = start; + while (p < end) { operation = *(njs_vmcode_operation_t *) p; + line = njs_lookup_line(code, p - start); if (operation == NJS_VMCODE_ARRAY) { array = (njs_vmcode_array_t *) p; - njs_printf("%05uz ARRAY %04Xz %uz%s\n", - p - start, (size_t) array->retval, + njs_printf("%5uD | %05uz ARRAY %04Xz %uz%s\n", + line, p - start, (size_t) array->retval, (size_t) array->length, array->ctor ? " INIT" : ""); p += sizeof(njs_vmcode_array_t); @@ -210,8 +219,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_IF_TRUE_JUMP) { cond_jump = (njs_vmcode_cond_jump_t *) p; - njs_printf("%05uz JUMP IF TRUE %04Xz %z\n", - p - start, (size_t) cond_jump->cond, + njs_printf("%5uD | %05uz JUMP IF TRUE %04Xz %z\n", + line, p - start, (size_t) cond_jump->cond, (size_t) cond_jump->offset); p += sizeof(njs_vmcode_cond_jump_t); @@ -222,8 +231,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_IF_FALSE_JUMP) { cond_jump = (njs_vmcode_cond_jump_t *) p; - njs_printf("%05uz JUMP IF FALSE %04Xz %z\n", - p - start, (size_t) cond_jump->cond, + njs_printf("%5uD | %05uz JUMP IF FALSE %04Xz %z\n", + line, p - start, (size_t) cond_jump->cond, (size_t) cond_jump->offset); p += sizeof(njs_vmcode_cond_jump_t); @@ -234,8 +243,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_JUMP) { jump = (njs_vmcode_jump_t *) p; - njs_printf("%05uz JUMP %z\n", - p - start, (size_t) jump->offset); + njs_printf("%5uD | %05uz JUMP %z\n", + line, p - start, (size_t) jump->offset); p += sizeof(njs_vmcode_jump_t); @@ -245,8 +254,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_IF_EQUAL_JUMP) { equal = (njs_vmcode_equal_jump_t *) p; - njs_printf("%05uz JUMP IF EQUAL %04Xz %04Xz %z\n", - p - start, (size_t) equal->value1, + njs_printf("%5uD | %05uz JUMP IF EQUAL %04Xz %04Xz %z\n", + line, p - start, (size_t) equal->value1, (size_t) equal->value2, (size_t) equal->offset); p += sizeof(njs_vmcode_equal_jump_t); @@ -257,8 +266,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TEST_IF_TRUE) { test_jump = (njs_vmcode_test_jump_t *) p; - njs_printf("%05uz TEST IF TRUE %04Xz %04Xz %z\n", - p - start, (size_t) test_jump->retval, + njs_printf("%5uD | %05uz TEST IF TRUE %04Xz %04Xz %z\n", + line, p - start, (size_t) test_jump->retval, (size_t) test_jump->value, (size_t) test_jump->offset); p += sizeof(njs_vmcode_test_jump_t); @@ -269,8 +278,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TEST_IF_FALSE) { test_jump = (njs_vmcode_test_jump_t *) p; - njs_printf("%05uz TEST IF FALSE %04Xz %04Xz %z\n", - p - start, (size_t) test_jump->retval, + njs_printf("%5uD | %05uz TEST IF FALSE %04Xz %04Xz %z\n", + line, p - start, (size_t) test_jump->retval, (size_t) test_jump->value, (size_t) test_jump->offset); p += sizeof(njs_vmcode_test_jump_t); @@ -281,8 +290,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_COALESCE) { test_jump = (njs_vmcode_test_jump_t *) p; - njs_printf("%05uz COALESCE %04Xz %04Xz %z\n", - p - start, (size_t) test_jump->retval, + njs_printf("%5uD | %05uz COALESCE %04Xz %04Xz %z\n", + line, p - start, (size_t) test_jump->retval, (size_t) test_jump->value, (size_t) test_jump->offset); p += sizeof(njs_vmcode_test_jump_t); @@ -293,9 +302,9 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_FUNCTION_FRAME) { function = (njs_vmcode_function_frame_t *) p; - njs_printf("%05uz FUNCTION FRAME %04Xz %uz%s\n", - p - start, (size_t) function->name, function->nargs, - function->ctor ? " CTOR" : ""); + njs_printf("%5uD | %05uz FUNCTION FRAME %04Xz %uz%s\n", + line, p - start, (size_t) function->name, + function->nargs, function->ctor ? " CTOR" : ""); p += sizeof(njs_vmcode_function_frame_t); @@ -305,8 +314,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_METHOD_FRAME) { method = (njs_vmcode_method_frame_t *) p; - njs_printf("%05uz METHOD FRAME %04Xz %04Xz %uz%s\n", - p - start, (size_t) method->object, + njs_printf("%5uD | %05uz METHOD FRAME %04Xz %04Xz %uz%s\n", + line, p - start, (size_t) method->object, (size_t) method->method, method->nargs, method->ctor ? " CTOR" : ""); @@ -317,8 +326,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_PROPERTY_FOREACH) { prop_foreach = (njs_vmcode_prop_foreach_t *) p; - njs_printf("%05uz PROP FOREACH %04Xz %04Xz %z\n", - p - start, (size_t) prop_foreach->next, + njs_printf("%5uD | %05uz PROP FOREACH %04Xz %04Xz %z\n", + line, p - start, (size_t) prop_foreach->next, (size_t) prop_foreach->object, (size_t) prop_foreach->offset); @@ -329,8 +338,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_PROPERTY_NEXT) { prop_next = (njs_vmcode_prop_next_t *) p; - njs_printf("%05uz PROP NEXT %04Xz %04Xz %04Xz %z\n", - p - start, (size_t) prop_next->retval, + njs_printf("%5uD | %05uz PROP NEXT %04Xz %04Xz %04Xz %z\n", + line, p - start, (size_t) prop_next->retval, (size_t) prop_next->object, (size_t) prop_next->next, (size_t) prop_next->offset); @@ -342,8 +351,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_PROPERTY_ACCESSOR) { prop_accessor = (njs_vmcode_prop_accessor_t *) p; - njs_printf("%05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n", - p - start, + njs_printf("%5uD | %05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n", + line, p - start, (prop_accessor->type == NJS_OBJECT_PROP_GETTER) ? "GET" : "SET", (size_t) prop_accessor->value, @@ -358,8 +367,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TRY_START) { try_start = (njs_vmcode_try_start_t *) p; - njs_printf("%05uz TRY START %04Xz %04Xz %z\n", - p - start, (size_t) try_start->exception_value, + njs_printf("%5uD | %05uz TRY START %04Xz %04Xz %z\n", + line, p - start, (size_t) try_start->exception_value, (size_t) try_start->exit_value, (size_t) try_start->offset); @@ -371,8 +380,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TRY_BREAK) { try_tramp = (njs_vmcode_try_trampoline_t *) p; - njs_printf("%05uz TRY BREAK %04Xz %z\n", - p - start, (size_t) try_tramp->exit_value, + njs_printf("%5uD | %05uz TRY BREAK %04Xz %z\n", + line, p - start, (size_t) try_tramp->exit_value, (size_t) try_tramp->offset); p += sizeof(njs_vmcode_try_trampoline_t); @@ -383,8 +392,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TRY_CONTINUE) { try_tramp = (njs_vmcode_try_trampoline_t *) p; - njs_printf("%05uz TRY CONTINUE %04Xz %z\n", - p - start, (size_t) try_tramp->exit_value, + njs_printf("%5uD | %05uz TRY CONTINUE %04Xz %z\n", + line, p - start, (size_t) try_tramp->exit_value, (size_t) try_tramp->offset); p += sizeof(njs_vmcode_try_trampoline_t); @@ -395,8 +404,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TRY_RETURN) { try_return = (njs_vmcode_try_return_t *) p; - njs_printf("%05uz TRY RETURN %04Xz %04Xz %z\n", - p - start, (size_t) try_return->save, + njs_printf("%5uD | %05uz TRY RETURN %04Xz %04Xz %z\n", + line, p - start, (size_t) try_return->save, (size_t) try_return->retval, (size_t) try_return->offset); @@ -408,8 +417,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_CATCH) { catch = (njs_vmcode_catch_t *) p; - njs_printf("%05uz CATCH %04Xz %z\n", - p - start, (size_t) catch->exception, + njs_printf("%5uD | %05uz CATCH %04Xz %z\n", + line, p - start, (size_t) catch->exception, (size_t) catch->offset); p += sizeof(njs_vmcode_catch_t); @@ -420,8 +429,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_TRY_END) { try_end = (njs_vmcode_try_end_t *) p; - njs_printf("%05uz TRY END %z\n", - p - start, (size_t) try_end->offset); + njs_printf("%5uD | %05uz TRY END %z\n", + line, p - start, (size_t) try_end->offset); p += sizeof(njs_vmcode_try_end_t); @@ -431,8 +440,8 @@ njs_disassemble(u_char *start, u_char *e if (operation == NJS_VMCODE_FINALLY) { finally = (njs_vmcode_finally_t *) p; - njs_printf("%05uz TRY FINALLY %04Xz %04Xz %z %z\n", - p - start, (size_t) finally->retval, + njs_printf("%5uD | %05uz TRY FINALLY %04Xz %04Xz %z %z\n", + line, p - start, (size_t) finally->retval, (size_t) finally->exit_value, (size_t) finally->continue_offset, (size_t) finally->break_offset); @@ -443,7 +452,7 @@ njs_disassemble(u_char *start, u_char *e } if (operation == NJS_VMCODE_REFERENCE_ERROR) { - njs_printf("%05uz REFERENCE ERROR\n", p - start); + njs_printf("%5uD | %05uz REFERENCE ERROR\n", line, p - start); p += sizeof(njs_vmcode_reference_error_t); @@ -460,23 +469,23 @@ njs_disassemble(u_char *start, u_char *e if (code_name->size == sizeof(njs_vmcode_3addr_t)) { code3 = (njs_vmcode_3addr_t *) p; - njs_printf("%05uz %*s %04Xz %04Xz %04Xz\n", - p - start, name->length, name->start, + njs_printf("%5uD | %05uz %*s %04Xz %04Xz %04Xz\n", + line, p - start, name->length, name->start, (size_t) code3->dst, (size_t) code3->src1, (size_t) code3->src2); } else if (code_name->size == sizeof(njs_vmcode_2addr_t)) { code2 = (njs_vmcode_2addr_t *) p; - njs_printf("%05uz %*s %04Xz %04Xz\n", - p - start, name->length, name->start, + njs_printf("%5uD | %05uz %*s %04Xz %04Xz\n", + line, p - start, name->length, name->start, (size_t) code2->dst, (size_t) code2->src); } else if (code_name->size == sizeof(njs_vmcode_1addr_t)) { code1 = (njs_vmcode_1addr_t *) p; - njs_printf("%05uz %*s %04Xz\n", - p - start, name->length, name->start, + njs_printf("%5uD | %05uz %*s %04Xz\n", + line, p - start, name->length, name->start, (size_t) code1->index); } @@ -490,7 +499,7 @@ njs_disassemble(u_char *start, u_char *e } while (n != 0); - njs_printf("%05uz UNKNOWN %04Xz\n", + njs_printf("%5uD | %05uz UNKNOWN %04Xz\n", line, p - start, (size_t) (uintptr_t) operation); p += sizeof(njs_vmcode_operation_t); diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_error.c --- a/src/njs_error.c Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs_error.c Thu Jun 18 18:56:24 2020 +0000 @@ -8,6 +8,19 @@ #include +typedef struct { + njs_str_t name; + njs_str_t file; + uint32_t line; +} njs_backtrace_entry_t; + + +static njs_int_t njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack, + njs_native_frame_t *native_frame); +static njs_int_t njs_backtrace_to_string(njs_vm_t *vm, njs_arr_t *backtrace, + njs_str_t *dst); + + static const njs_value_t njs_error_message_string = njs_string("message"); static const njs_value_t njs_error_name_string = njs_string("name"); static const njs_value_t njs_error_stack_string = njs_string("stack"); @@ -84,7 +97,9 @@ njs_error_stack_new(njs_vm_t *vm, njs_ob frame = vm->top_frame; for ( ;; ) { - if (njs_vm_add_backtrace_entry(vm, stack, frame) != NJS_OK) { + if ((frame->native || frame->pc != NULL) + && njs_add_backtrace_entry(vm, stack, frame) != NJS_OK) + { break; } @@ -97,7 +112,7 @@ njs_error_stack_new(njs_vm_t *vm, njs_ob njs_string_get(retval, &string); - ret = njs_vm_backtrace_to_string(vm, stack, &string); + ret = njs_backtrace_to_string(vm, stack, &string); njs_arr_destroy(stack); @@ -121,7 +136,7 @@ njs_error_stack_attach(njs_vm_t *vm, njs return NJS_DECLINED; } - if (vm->debug == NULL || vm->start == NULL) { + if (njs_slow_path(!vm->options.backtrace || vm->start == NULL)) { return NJS_OK; } @@ -1147,3 +1162,117 @@ const njs_object_type_init_t njs_uri_er .prototype_props = &njs_uri_error_prototype_init, .prototype_value = { .object = { .type = NJS_OBJECT } }, }; + + +static njs_int_t +njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack, + njs_native_frame_t *native_frame) +{ + njs_int_t ret; + njs_uint_t i; + njs_vm_code_t *code; + njs_function_t *function; + njs_backtrace_entry_t *be; + + function = native_frame->function; + + be = njs_arr_add(stack); + if (njs_slow_path(be == NULL)) { + return NJS_ERROR; + } + + be->line = 0; + be->file = njs_str_value(""); + + if (function != NULL && function->native) { + while (function->bound != NULL) { + function = function->u.bound_target; + } + + ret = njs_builtin_match_native_function(vm, function, &be->name); + if (ret == NJS_OK) { + return NJS_OK; + } + + be->name = njs_entry_native; + + return NJS_OK; + } + + code = vm->codes->start; + + for (i = 0; i < vm->codes->items; i++, code++) { + if (code->start <= native_frame->pc + && native_frame->pc < code->end) + { + be->name = code->name; + be->line = njs_lookup_line(code, native_frame->pc - code->start); + if (!vm->options.quiet) { + be->file = code->file; + } + + return NJS_OK; + } + } + + be->name = njs_entry_unknown; + + return NJS_OK; +} + + +static njs_int_t +njs_backtrace_to_string(njs_vm_t *vm, njs_arr_t *backtrace, njs_str_t *dst) +{ + size_t count; + njs_chb_t chain; + njs_uint_t i; + njs_backtrace_entry_t *be, *prev; + + if (backtrace->items == 0) { + return NJS_OK; + } + + njs_chb_init(&chain, vm->mem_pool); + + njs_chb_append_str(&chain, dst); + njs_chb_append(&chain, "\n", 1); + + count = 0; + prev = NULL; + + be = backtrace->start; + + for (i = 0; i < backtrace->items; i++) { + if (i != 0 && prev->name.start == be->name.start + && prev->line == be->line) + { + count++; + + } else { + if (count != 0) { + njs_chb_sprintf(&chain, 64, " repeats %uz times\n", count); + count = 0; + } + + njs_chb_sprintf(&chain, 10 + be->name.length, " at %V ", + &be->name); + + if (be->line != 0) { + njs_chb_sprintf(&chain, 12 + be->file.length, + "(%V:%uD)\n", &be->file, be->line); + + } else { + njs_chb_append(&chain, "(native)\n", 9); + } + } + + prev = be; + be++; + } + + njs_chb_join(&chain, dst); + njs_chb_destroy(&chain); + + return NJS_OK; +} diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_function.c --- a/src/njs_function.c Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs_function.c Thu Jun 18 18:56:24 2020 +0000 @@ -371,6 +371,7 @@ njs_function_native_frame(njs_vm_t *vm, frame->nargs = function->args_offset + nargs; frame->ctor = ctor; frame->native = 1; + frame->pc = NULL; value = (njs_value_t *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE); frame->arguments = value; @@ -454,6 +455,7 @@ njs_function_lambda_frame(njs_vm_t *vm, native_frame->nargs = nargs; native_frame->ctor = ctor; native_frame->native = 0; + native_frame->pc = NULL; /* Function arguments. */ @@ -851,11 +853,11 @@ njs_function_constructor(njs_vm_t *vm, n njs_value_t *body; njs_lexer_t lexer; njs_parser_t *parser; + njs_vm_code_t *code; njs_function_t *function; njs_generator_t generator; njs_parser_scope_t *scope; njs_function_lambda_t *lambda; - njs_vmcode_function_t *code; if (!vm->options.unsafe) { body = njs_argument(args, nargs - 1); @@ -949,15 +951,18 @@ njs_function_constructor(njs_vm_t *vm, n njs_memzero(&generator, sizeof(njs_generator_t)); - ret = njs_generate_scope(vm, &generator, scope, &njs_entry_anonymous); - if (njs_slow_path(ret != NJS_OK)) { - return ret; + code = njs_generate_scope(vm, &generator, scope, &njs_entry_anonymous); + if (njs_slow_path(code == NULL)) { + if (!njs_is_error(&vm->retval)) { + njs_internal_error(vm, "njs_generate_scope() failed"); + } + + return NJS_ERROR; } njs_chb_destroy(&chain); - code = (njs_vmcode_function_t *) generator.code_start; - lambda = code->lambda; + lambda = ((njs_vmcode_function_t *) generator.code_start)->lambda; function = njs_function_alloc(vm, lambda, NULL, 0); if (njs_slow_path(function == NULL)) { diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_function.h --- a/src/njs_function.h Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs_function.h Thu Jun 18 18:56:24 2020 +0000 @@ -44,6 +44,7 @@ struct njs_function_lambda_s { struct njs_native_frame_s { u_char *free; + u_char *pc; njs_function_t *function; njs_native_frame_t *previous; diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_generator.c --- a/src/njs_generator.c Wed Jun 17 14:38:23 2020 +0000 +++ b/src/njs_generator.c Thu Jun 18 18:56:24 2020 +0000 @@ -57,6 +57,8 @@ static njs_int_t njs_generator(njs_vm_t njs_parser_node_t *node); static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator, size_t size); +static njs_int_t njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node, u_char *code); static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, @@ -179,18 +181,20 @@ static njs_int_t njs_generate_global_ref static njs_int_t njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); -static njs_int_t njs_generate_function_debug(njs_vm_t *vm, - const njs_str_t *name, njs_function_lambda_t *lambda, - njs_parser_node_t *node); - - -#define njs_generate_code(generator, type, _code, _op, nargs) \ + +#define njs_generate_code(generator, type, _code, _op, nargs, nd) \ do { \ _code = (type *) njs_generate_reserve(vm, generator, sizeof(type)); \ if (njs_slow_path(_code == NULL)) { \ return NJS_ERROR; \ } \ \ + if (njs_generate_code_map(vm, generator, nd, (u_char *) _code) \ + != NJS_OK) \ + { \ + return NJS_ERROR; \ + } \ + \ generator->code_end += sizeof(type); \ \ _code->code.operation = _op; \ @@ -201,15 +205,15 @@ static njs_int_t njs_generate_function_d #define njs_generate_code_jump(generator, _code, _offset) \ do { \ njs_generate_code(generator, njs_vmcode_jump_t, _code, \ - NJS_VMCODE_JUMP, 0); \ + NJS_VMCODE_JUMP, 0, NULL); \ _code->offset = _offset; \ } while (0) -#define njs_generate_code_move(generator, _code, _dst, _src) \ +#define njs_generate_code_move(generator, _code, _dst, _src, node) \ do { \ njs_generate_code(generator, njs_vmcode_move_t, _code, \ - NJS_VMCODE_MOVE, 2); \ + NJS_VMCODE_MOVE, 2, node); \ _code->dst = _dst; \ _code->src = _src; \ } while (0) @@ -536,6 +540,54 @@ njs_generate_reserve(njs_vm_t *vm, njs_g static njs_int_t +njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node, u_char *code) +{ + njs_arr_t *map; + njs_vm_line_num_t *last; + + map = generator->lines; + + if (map != NULL && node != NULL) { + last = (map->items != 0) ? njs_arr_last(map) : NULL; + if (last == NULL || (node->token_line != last->line)) { + last = njs_arr_add(map); + if (njs_slow_path(last == NULL)) { + return NJS_ERROR; + } + + last->line = node->token_line; + last->offset = njs_code_offset(generator, code); + } + } + + return NJS_OK; +} + + +uint32_t +njs_lookup_line(njs_vm_code_t *code, uint32_t offset) +{ + njs_uint_t n; + njs_vm_line_num_t *map; + + n = (code->lines != NULL) ? code->lines->items : 0; + map = (njs_vm_line_num_t *) code->lines->start; + + while (n != 0) { + if (offset >= map->offset && (n == 1 || offset < map[1].offset)) { + return map->line; + } + + map++; + n--; + } + + return 0; +} + + +static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) { @@ -552,7 +604,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene } njs_generate_code(generator, njs_vmcode_object_copy_t, copy, - NJS_VMCODE_OBJECT_COPY, 2); + NJS_VMCODE_OBJECT_COPY, 2, node); copy->retval = node->index; copy->object = var->index; @@ -626,7 +678,8 @@ njs_generate_var_statement(njs_vm_t *vm, * empty object or expression result is stored directly in variable. */ if (lvalue->index != expr->index) { - njs_generate_code_move(generator, move, lvalue->index, expr->index); + njs_generate_code_move(generator, move, lvalue->index, expr->index, + lvalue); } node->index = expr->index; @@ -653,7 +706,7 @@ njs_generate_if_statement(njs_vm_t *vm, } njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump, - NJS_VMCODE_IF_FALSE_JUMP, 2); + NJS_VMCODE_IF_FALSE_JUMP, 2, node); cond_jump->cond = node->left->index; ret = njs_generate_node_index_release(vm, generator, node->left); @@ -728,7 +781,7 @@ njs_generate_cond_expression(njs_vm_t *v } njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump, - NJS_VMCODE_IF_FALSE_JUMP, 2); + NJS_VMCODE_IF_FALSE_JUMP, 2, node); cond_jump_offset = njs_code_offset(generator, cond_jump); cond_jump->cond = node->left->index; @@ -755,7 +808,7 @@ njs_generate_cond_expression(njs_vm_t *v if (node->index != branch->left->index) { njs_generate_code_move(generator, move, node->index, - branch->left->index); + branch->left->index, node); } ret = njs_generate_node_index_release(vm, generator, branch->left); @@ -778,7 +831,7 @@ njs_generate_cond_expression(njs_vm_t *v if (node->index != branch->right->index) { njs_generate_code_move(generator, move, node->index, - branch->right->index); + branch->right->index, node); } njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t, jump_offset); @@ -822,7 +875,7 @@ njs_generate_switch_statement(njs_vm_t * return NJS_ERROR; } - njs_generate_code_move(generator, move, index, expr->index); + njs_generate_code_move(generator, move, index, expr->index, swtch); } ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_SWITCH, @@ -848,7 +901,7 @@ njs_generate_switch_statement(njs_vm_t * } njs_generate_code(generator, njs_vmcode_equal_jump_t, equal, - NJS_VMCODE_IF_EQUAL_JUMP, 3); + NJS_VMCODE_IF_EQUAL_JUMP, 3, branch); equal->offset = offsetof(njs_vmcode_equal_jump_t, offset); equal->value1 = index; equal->value2 = node->left->index; @@ -971,7 +1024,7 @@ njs_generate_while_statement(njs_vm_t *v } njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump, - NJS_VMCODE_IF_TRUE_JUMP, 2); + NJS_VMCODE_IF_TRUE_JUMP, 2, condition); cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump); cond_jump->cond = condition->index; @@ -1017,7 +1070,7 @@ njs_generate_do_while_statement(njs_vm_t } njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump, - NJS_VMCODE_IF_TRUE_JUMP, 2); + NJS_VMCODE_IF_TRUE_JUMP, 2, condition); cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump); cond_jump->cond = condition->index; @@ -1111,7 +1164,7 @@ njs_generate_for_statement(njs_vm_t *vm, } njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump, - NJS_VMCODE_IF_TRUE_JUMP, 2); + NJS_VMCODE_IF_TRUE_JUMP, 2, condition); cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump); cond_jump->cond = condition->index; @@ -1156,7 +1209,7 @@ njs_generate_for_in_statement(njs_vm_t * } njs_generate_code(generator, njs_vmcode_prop_foreach_t, prop_foreach, - NJS_VMCODE_PROPERTY_FOREACH, 2); + NJS_VMCODE_PROPERTY_FOREACH, 2, foreach); prop_offset = njs_code_offset(generator, prop_foreach); prop_foreach->object = foreach->right->index; @@ -1188,7 +1241,7 @@ njs_generate_for_in_statement(njs_vm_t * } njs_generate_code(generator, njs_vmcode_prop_next_t, prop_next, - NJS_VMCODE_PROPERTY_NEXT, 3); + NJS_VMCODE_PROPERTY_NEXT, 3, node->left->left); prop_offset = njs_code_offset(generator, prop_next); prop_next->retval = foreach->left->index; prop_next->object = foreach->right->index; @@ -1575,7 +1628,7 @@ njs_generate_stop_statement(njs_vm_t *vm if (njs_fast_path(ret == NJS_OK)) { njs_generate_code(generator, njs_vmcode_stop_t, stop, - NJS_VMCODE_STOP, 1); + NJS_VMCODE_STOP, 1, node); index = NJS_INDEX_NONE; node = node->right; @@ -1645,7 +1698,8 @@ njs_generate_assignment(njs_vm_t *vm, nj * empty object or expression result is stored directly in variable. */ if (lvalue->index != expr->index) { - njs_generate_code_move(generator, move, lvalue->index, expr->index); + njs_generate_code_move(generator, move, lvalue->index, expr->index, + expr); } node->index = expr->index; @@ -1687,7 +1741,7 @@ njs_generate_assignment(njs_vm_t *vm, nj return NJS_ERROR; } - njs_generate_code_move(generator, move, index, src); + njs_generate_code_move(generator, move, index, src, object); } if (property->token_type == NJS_TOKEN_NAME) { @@ -1698,7 +1752,7 @@ njs_generate_assignment(njs_vm_t *vm, nj return NJS_ERROR; } - njs_generate_code_move(generator, move, index, src); + njs_generate_code_move(generator, move, index, src, property); } } @@ -1710,18 +1764,18 @@ njs_generate_assignment(njs_vm_t *vm, nj switch (lvalue->token_type) { case NJS_TOKEN_PROPERTY_INIT: njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set, - NJS_VMCODE_PROPERTY_INIT, 3); + NJS_VMCODE_PROPERTY_INIT, 3, expr); break; case NJS_TOKEN_PROTO_INIT: njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set, - NJS_VMCODE_PROTO_INIT, 3); + NJS_VMCODE_PROTO_INIT, 3, expr); break; default: /* NJS_VMCODE_PROPERTY_SET */ njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set, - NJS_VMCODE_PROPERTY_SET, 3); + NJS_VMCODE_PROPERTY_SET, 3, expr); } prop_set->value = expr->index; @@ -1763,7 +1817,7 @@ njs_generate_operation_assignment(njs_vm /* Preserve variable value if it may be changed by expression. */ njs_generate_code(generator, njs_vmcode_move_t, move, - NJS_VMCODE_MOVE, 2); + NJS_VMCODE_MOVE, 2, expr); move->src = lvalue->index; index = njs_generate_temp_index_get(vm, generator, expr); @@ -1780,7 +1834,7 @@ njs_generate_operation_assignment(njs_vm } njs_generate_code(generator, njs_vmcode_3addr_t, code, - node->u.operation, 3); + node->u.operation, 3, expr); code->dst = lvalue->index; code->src1 = index; code->src2 = expr->index; @@ -1823,7 +1877,7 @@ njs_generate_operation_assignment(njs_vm } njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get, - NJS_VMCODE_PROPERTY_GET, 3); + NJS_VMCODE_PROPERTY_GET, 3, property); prop_get->value = index; prop_get->object = object->index; prop_get->property = property->index; @@ -1836,13 +1890,13 @@ njs_generate_operation_assignment(njs_vm } njs_generate_code(generator, njs_vmcode_3addr_t, code, - node->u.operation, 3); + node->u.operation, 3, expr); code->dst = node->index; code->src1 = node->index; code->src2 = expr->index; njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set, - NJS_VMCODE_PROPERTY_SET, 3); + NJS_VMCODE_PROPERTY_SET, 3, expr); prop_set->value = node->index; prop_set->object = object->index; prop_set->property = property->index; @@ -1868,7 +1922,7 @@ njs_generate_object(njs_vm_t *vm, njs_ge } njs_generate_code(generator, njs_vmcode_object_t, object, - NJS_VMCODE_OBJECT, 1); + NJS_VMCODE_OBJECT, 1, node); object->retval = node->index; /* Initialize object. */ @@ -1907,7 +1961,7 @@ njs_generate_property_accessor(njs_vm_t } njs_generate_code(generator, njs_vmcode_prop_accessor_t, accessor, - NJS_VMCODE_PROPERTY_ACCESSOR, 3); + NJS_VMCODE_PROPERTY_ACCESSOR, 3, function); accessor->value = function->index; accessor->object = object->index; @@ -1931,7 +1985,7 @@ njs_generate_array(njs_vm_t *vm, njs_gen } njs_generate_code(generator, njs_vmcode_array_t, array, - NJS_VMCODE_ARRAY, 1); + NJS_VMCODE_ARRAY, 1, node); array->ctor = node->ctor; array->retval = node->index; array->length = node->u.length; @@ -1957,21 +2011,12 @@ njs_generate_function(njs_vm_t *vm, njs_ name = module ? &njs_entry_module : &njs_entry_anonymous; ret = njs_generate_function_scope(vm, lambda, node, name); - if (njs_slow_path(ret != NJS_OK)) { return ret; } - if (vm->debug != NULL) { - ret = njs_generate_function_debug(vm, name, lambda, - module ? node->right : node); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - } - njs_generate_code(generator, njs_vmcode_function_t, function, - NJS_VMCODE_FUNCTION, 1); + NJS_VMCODE_FUNCTION, 1, node); function->lambda = lambda; node->index = njs_generate_object_dest_index(vm, generator, node); @@ -1997,7 +2042,7 @@ njs_generate_regexp(njs_vm_t *vm, njs_ge } njs_generate_code(generator, njs_vmcode_regexp_t, regexp, - NJS_VMCODE_REGEXP, 1); + NJS_VMCODE_REGEXP, 1, node); regexp->retval = node->index; regexp->pattern = node->u.value.data.u.data; @@ -2018,7 +2063,7 @@ njs_generate_template_literal(njs_vm_t * } njs_generate_code(generator, njs_vmcode_template_literal_t, code, - NJS_VMCODE_TEMPLATE_LITERAL, 1); + NJS_VMCODE_TEMPLATE_LITERAL, 1, node); code->retval = node->left->index; node->index = node->left->index; @@ -2042,7 +2087,7 @@ njs_generate_test_jump_expression(njs_vm } njs_generate_code(generator, njs_vmcode_test_jump_t, test_jump, - node->u.operation, 2); + node->u.operation, 2, node); jump_offset = njs_code_offset(generator, test_jump); test_jump->value = node->left->index; @@ -2066,7 +2111,7 @@ njs_generate_test_jump_expression(njs_vm if (node->index != node->right->index) { njs_generate_code_move(generator, move, node->index, - node->right->index); + node->right->index, node); } njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, jump_offset); @@ -2098,7 +2143,7 @@ njs_generate_3addr_operation(njs_vm_t *v From xeioex at nginx.com Thu Jun 18 18:56:36 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 18 Jun 2020 18:56:36 +0000 Subject: [njs] Optimizing njs_builtin_match_native_function() for speed. Message-ID: details: https://hg.nginx.org/njs/rev/a712d6442c0a branches: changeset: 1436:a712d6442c0a user: Dmitry Volyntsev date: Thu Jun 18 18:56:24 2020 +0000 description: Optimizing njs_builtin_match_native_function() for speed. diffstat: src/njs_builtin.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/njs_vm.h | 2 + 2 files changed, 58 insertions(+), 7 deletions(-) diffs (120 lines): diff -r ea2ec4c3ed7d -r a712d6442c0a src/njs_builtin.c --- a/src/njs_builtin.c Thu Jun 18 18:56:24 2020 +0000 +++ b/src/njs_builtin.c Thu Jun 18 18:56:24 2020 +0000 @@ -688,17 +688,45 @@ done: } +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_uint_t i; + njs_uint_t i, n; njs_value_t value; njs_module_t *module; njs_lvlhsh_each_t lhe; + 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; @@ -710,8 +738,7 @@ njs_builtin_match_native_function(njs_vm njs_builtin_traverse); if (ret == NJS_DONE) { - *name = ctx.match; - return NJS_OK; + goto found; } /* Constructor from built-in modules (not-mapped to global object). */ @@ -730,8 +757,7 @@ njs_builtin_match_native_function(njs_vm njs_builtin_traverse); if (ret == NJS_DONE) { - *name = ctx.match; - return NJS_OK; + goto found; } } @@ -752,12 +778,35 @@ njs_builtin_match_native_function(njs_vm njs_builtin_traverse); if (ret == NJS_DONE) { - *name = ctx.match; - return NJS_OK; + 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; } diff -r ea2ec4c3ed7d -r a712d6442c0a src/njs_vm.h --- a/src/njs_vm.h Thu Jun 18 18:56:24 2020 +0000 +++ b/src/njs_vm.h Thu Jun 18 18:56:24 2020 +0000 @@ -223,6 +223,8 @@ struct njs_vm_s { njs_uint_t main_index; njs_arr_t *codes; /* of njs_vm_code_t */ + njs_arr_t *functions_name_cache; + njs_trace_t trace; njs_random_t random; From takada at jocdn.co.jp Fri Jun 19 00:41:37 2020 From: takada at jocdn.co.jp (TAKADA Sokichi) Date: Fri, 19 Jun 2020 09:41:37 +0900 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache Message-ID: # HG changeset patch # User TAKADA Sokichi # Date 1592383243 -32400 # Wed Jun 17 17:40:43 2020 +0900 # Node ID d5bbe3ad1f1491125485786aacc5d219c81801d1 # Parent 8cf31489b479b689b7ff4a9601ce24c914d0394c skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache "ngx_http_upstream_process_accel_expires" is calculate and set valid_date value when a request respond by a cache, even though it will never use in the response. This patch to skip unnecessary process. On the other hands, this has good side effect to can get TRUE valid_date value of the cache file in "header filter" and "log" hook handler. i.e. I would like to get the TRUE valid_date of cache in header_filter_by_lua or log_by_lua handlers. diff -r 8cf31489b479 -r d5bbe3ad1f14 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Mon Jun 15 17:35:26 2020 -0400 +++ b/src/http/ngx_http_upstream.c Wed Jun 17 17:40:43 2020 +0900 @@ -4776,6 +4776,10 @@ return NGX_OK; } + if (r->cached == 1) { + return NGX_OK; + } + len = h->value.len; p = h->value.data; From arut at nginx.com Fri Jun 19 14:02:03 2020 From: arut at nginx.com (Roman Arutyunyan) Date: Fri, 19 Jun 2020 14:02:03 +0000 Subject: [nginx] OCSP: fixed use-after-free on error. Message-ID: details: https://hg.nginx.org/nginx/rev/1ece2ac2555a branches: changeset: 7667:1ece2ac2555a user: Roman Arutyunyan date: Mon Jun 15 20:17:16 2020 +0300 description: OCSP: fixed use-after-free on error. When validating second and further certificates, ssl callback could be called twice to report the error. After the first call client connection is terminated and its memory is released. Prior to the second call and in it released connection memory is accessed. Errors triggering this behavior: - failure to create the request - failure to start resolving OCSP responder name - failure to start connecting to the OCSP responder The fix is to rearrange the code to eliminate the second call. diffstat: src/event/ngx_event_openssl_stapling.c | 43 ++++++++++++++++----------------- 1 files changed, 21 insertions(+), 22 deletions(-) diffs (108 lines): diff -r 8cf31489b479 -r 1ece2ac2555a src/event/ngx_event_openssl_stapling.c --- a/src/event/ngx_event_openssl_stapling.c Mon Jun 15 17:35:26 2020 -0400 +++ b/src/event/ngx_event_openssl_stapling.c Mon Jun 15 20:17:16 2020 +0300 @@ -980,6 +980,7 @@ ngx_ssl_ocsp_validate_next(ngx_connectio if (ocsp->ncert == n - 1 || (ocf->depth == 2 && ocsp->ncert == 1)) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl ocsp validated, certs:%ui", ocsp->ncert); + rc = NGX_OK; goto done; } @@ -988,7 +989,8 @@ ngx_ssl_ocsp_validate_next(ngx_connectio ctx = ngx_ssl_ocsp_start(c->log); if (ctx == NULL) { - goto failed; + rc = NGX_ERROR; + goto done; } ocsp->ctx = ctx; @@ -1012,8 +1014,9 @@ ngx_ssl_ocsp_validate_next(ngx_connectio ctx->uri = ocf->uri; ctx->port = ocf->port; - if (ngx_ssl_ocsp_responder(c, ctx) != NGX_OK) { - goto failed; + rc = ngx_ssl_ocsp_responder(c, ctx); + if (rc != NGX_OK) { + goto done; } if (ctx->uri.len == 0) { @@ -1025,7 +1028,7 @@ ngx_ssl_ocsp_validate_next(ngx_connectio rc = ngx_ssl_ocsp_cache_lookup(ctx); if (rc == NGX_ERROR) { - goto failed; + goto done; } if (rc == NGX_DECLINED) { @@ -1051,12 +1054,12 @@ ngx_ssl_ocsp_validate_next(ngx_connectio done: - ocsp->status = NGX_OK; - return; - -failed: - - ocsp->status = NGX_ERROR; + ocsp->status = rc; + + if (c->ssl->in_ocsp) { + c->ssl->handshaked = 1; + c->ssl->handler(c); + } } @@ -1073,22 +1076,16 @@ ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t rc = ngx_ssl_ocsp_verify(ctx); if (rc != NGX_OK) { - ocsp->status = rc; - ngx_ssl_ocsp_done(ctx); goto done; } rc = ngx_ssl_ocsp_cache_store(ctx); if (rc != NGX_OK) { - ocsp->status = rc; - ngx_ssl_ocsp_done(ctx); goto done; } if (ctx->status != V_OCSP_CERTSTATUS_GOOD) { ocsp->cert_status = ctx->status; - ocsp->status = NGX_OK; - ngx_ssl_ocsp_done(ctx); goto done; } @@ -1096,15 +1093,17 @@ ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t ngx_ssl_ocsp_validate_next(c); + return; + done: - if (ocsp->status == NGX_AGAIN || !c->ssl->in_ocsp) { - return; + ocsp->status = rc; + ngx_ssl_ocsp_done(ctx); + + if (c->ssl->in_ocsp) { + c->ssl->handshaked = 1; + c->ssl->handler(c); } - - c->ssl->handshaked = 1; - - c->ssl->handler(c); } From alexander.borisov at nginx.com Fri Jun 19 16:50:27 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 19 Jun 2020 16:50:27 +0000 Subject: [njs] Parser: fixed heap-use-after-free in optional chain. Message-ID: details: https://hg.nginx.org/njs/rev/341cd52d4348 branches: changeset: 1437:341cd52d4348 user: Alexander Borisov date: Fri Jun 19 19:48:12 2020 +0300 description: Parser: fixed heap-use-after-free in optional chain. diffstat: src/njs_parser.c | 4 ---- src/test/njs_unit_test.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diffs (27 lines): diff -r a712d6442c0a -r 341cd52d4348 src/njs_parser.c --- a/src/njs_parser.c Thu Jun 18 18:56:24 2020 +0000 +++ b/src/njs_parser.c Fri Jun 19 19:48:12 2020 +0300 @@ -2881,10 +2881,6 @@ njs_parser_optional_chain(njs_parser_t * break; default: - if (!njs_lexer_token_is_identifier_name(token)) { - njs_lexer_consume_token(parser->lexer, 1); - } - ret = njs_parser_property(parser, token, current); switch (ret) { diff -r a712d6442c0a -r 341cd52d4348 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Jun 18 18:56:24 2020 +0000 +++ b/src/test/njs_unit_test.c Fri Jun 19 19:48:12 2020 +0300 @@ -17016,6 +17016,9 @@ static njs_unit_test_t njs_test[] = { njs_str("{{} ({a: 1, b: {}\n}\n})\n}"), njs_str("SyntaxError: Unexpected token \"}\" in 3") }, + + { njs_str("object?."), + njs_str("SyntaxError: Unexpected end of input in 1") }, }; From alexander.borisov at nginx.com Fri Jun 19 16:50:29 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Fri, 19 Jun 2020 16:50:29 +0000 Subject: [njs] Parser: fixed line counting in template literals. Message-ID: details: https://hg.nginx.org/njs/rev/7d24976ced90 branches: changeset: 1438:7d24976ced90 user: Alexander Borisov date: Fri Jun 19 19:48:13 2020 +0300 description: Parser: fixed line counting in template literals. This closes #321 issue on GitHub. diffstat: src/njs_parser.c | 28 +++++++++++++++++----------- src/test/njs_unit_test.c | 7 +++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diffs (97 lines): diff -r 341cd52d4348 -r 7d24976ced90 src/njs_parser.c --- a/src/njs_parser.c Fri Jun 19 19:48:12 2020 +0300 +++ b/src/njs_parser.c Fri Jun 19 19:48:13 2020 +0300 @@ -1141,7 +1141,7 @@ njs_parser_primary_expression_test(njs_p parser->node = node; njs_parser_next(parser, njs_parser_template_literal); - break; + return NJS_OK; /* CoverParenthesizedExpressionAndArrowParameterList */ case NJS_TOKEN_OPEN_PARENTHESIS: @@ -1322,6 +1322,9 @@ njs_parser_template_literal(njs_parser_t parser->target = temp; + token->text.start++; + token->text.length = 0; + njs_parser_next(parser, njs_parser_template_literal_string); return NJS_OK; @@ -2199,8 +2202,6 @@ njs_parser_property(njs_parser_t *parser parser->node = node; - njs_lexer_consume_token(parser->lexer, 1); - njs_parser_next(parser, njs_parser_template_literal); break; @@ -7820,28 +7821,33 @@ njs_parser_template_string(njs_parser_t c = *p++; - if (c == '\\') { + switch (c) { + case '\\': if (p == lexer->end) { - break; + return NJS_ERROR; } p++; escape = 1; continue; - } - - if (c == '`') { + + case '`': text->length = p - text->start - 1; goto done; - } - - if (c == '$') { + + case '$': if (p < lexer->end && *p == '{') { p++; text->length = p - text->start - 2; goto done; } + + break; + + case '\n': + parser->lexer->line++; + break; } } diff -r 341cd52d4348 -r 7d24976ced90 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Jun 19 19:48:12 2020 +0300 +++ b/src/test/njs_unit_test.c Fri Jun 19 19:48:13 2020 +0300 @@ -6330,6 +6330,9 @@ static njs_unit_test_t njs_test[] = "foo`That ${person} is a ${age}`;"), njs_str("That is a Mike21") }, + { njs_str("`\n`.length"), + njs_str("1") }, + /* Strings. */ { njs_str("var a = '0123456789' + '012345';" @@ -17889,6 +17892,10 @@ static njs_unit_test_t njs_shell_test[] njs_str("ReferenceError: \"a\" is not defined in 2\n" " at main (:2)\n") }, + { njs_str("\n`\n${Object}\n${a}`" ENTER), + njs_str("ReferenceError: \"a\" is not defined in 4\n" + " at main (:4)\n") }, + { njs_str("function log(v) {}\nlog({}\n.a\n.a)" ENTER), njs_str("TypeError: cannot get property \"a\" of undefined\n" " at main (:4)\n") }, From mdounin at mdounin.ru Sun Jun 21 21:11:15 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Jun 2020 00:11:15 +0300 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache In-Reply-To: References: Message-ID: <20200621211115.GA12747@mdounin.ru> Hello! On Fri, Jun 19, 2020 at 09:41:37AM +0900, TAKADA Sokichi wrote: > # HG changeset patch > # User TAKADA Sokichi > # Date 1592383243 -32400 > # Wed Jun 17 17:40:43 2020 +0900 > # Node ID d5bbe3ad1f1491125485786aacc5d219c81801d1 > # Parent 8cf31489b479b689b7ff4a9601ce24c914d0394c > skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache > > "ngx_http_upstream_process_accel_expires" is calculate and set valid_date value when a request respond by a cache, even though it will never use in the response. > This patch to skip unnecessary process. > > On the other hands, this has good side effect to can get TRUE valid_date value of the cache file in "header filter" and "log" hook handler. > i.e. I would like to get the TRUE valid_date of cache in header_filter_by_lua or log_by_lua handlers. > > diff -r 8cf31489b479 -r d5bbe3ad1f14 src/http/ngx_http_upstream.c > --- a/src/http/ngx_http_upstream.c Mon Jun 15 17:35:26 2020 -0400 > +++ b/src/http/ngx_http_upstream.c Wed Jun 17 17:40:43 2020 +0900 > @@ -4776,6 +4776,10 @@ > return NGX_OK; > } > > + if (r->cached == 1) { > + return NGX_OK; > + } > + > len = h->value.len; > p = h->value.data; Thanks for the patch. The cache validity time as obtained from cached responses is used while processing 304 responses during cache revalidation, so the suggested change looks wrong to me. -- Maxim Dounin http://mdounin.ru/ From takada at jocdn.co.jp Mon Jun 22 08:09:16 2020 From: takada at jocdn.co.jp (Sokichi Takada) Date: Mon, 22 Jun 2020 17:09:16 +0900 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache In-Reply-To: <20200621211115.GA12747@mdounin.ru> References: <20200621211115.GA12747@mdounin.ru> Message-ID: Hello! Thanks for the response. > The cache validity time as obtained from cached responses is used > while processing 304 responses during cache revalidation, so the > suggested change looks wrong to me. When processing 304 responses during cache revalidation, ngx_http_upstream_process_accel_expires is called twice. 1st time, in "ngx_http_upstream_process_header" function. src/http/ngx_http_upstream.c: 2387 rc = u->process_header(r); # process_header = ngx_http_upstream_process_accel_expires This calculates the exact valid_sec value by x-accel-expires of upstream's response, It doesn't use a value of the cache data. Also, the r->cached is 0 at this time. 2nd time, in "ngx_http_upstream_process_header" -> "ngx_http_upstream_test_next" -> "ngx_http_upstream_cache_send" function. src/http/ngx_http_upstream.c: 2423 if (ngx_http_upstream_test_next(r, u) == NGX_OK) -> src/http/ngx_http_upstream.c: 2535 rc = ngx_http_upstream_cache_send(r, u); -> src/http/ngx_http_upstream.c: 1073 rc = u->process_header(r); This calculates unnecessary valid_sec value by x-accel-expires of the cache data. Also, this calculation can skip by this patch since the r->cached is 1 at this time. Please look into ngx_http_upstream_test_next. It keeps the valid_sec value of 1st time into "valid" variable at "2523 valid = r->cache->valid_sec;". After that, it "calls ngx_http_upstream_cache_send", then updates cache data with the "valid" variable at "2560 r->cache->valid_sec = valid;". -- TAKADA Sokichi On Mon, Jun 22, 2020 at 6:11 AM Maxim Dounin wrote: > Hello! > > On Fri, Jun 19, 2020 at 09:41:37AM +0900, TAKADA Sokichi wrote: > > > # HG changeset patch > > # User TAKADA Sokichi > > # Date 1592383243 -32400 > > # Wed Jun 17 17:40:43 2020 +0900 > > # Node ID d5bbe3ad1f1491125485786aacc5d219c81801d1 > > # Parent 8cf31489b479b689b7ff4a9601ce24c914d0394c > > skip apply "ngx_http_upstream_process_accel_expires" when a request > responeded by cache > > > > "ngx_http_upstream_process_accel_expires" is calculate and set > valid_date value when a request respond by a cache, even though it will > never use in the response. > > This patch to skip unnecessary process. > > > > On the other hands, this has good side effect to can get TRUE valid_date > value of the cache file in "header filter" and "log" hook handler. > > i.e. I would like to get the TRUE valid_date of cache in > header_filter_by_lua or log_by_lua handlers. > > > > diff -r 8cf31489b479 -r d5bbe3ad1f14 src/http/ngx_http_upstream.c > > --- a/src/http/ngx_http_upstream.c Mon Jun 15 17:35:26 2020 -0400 > > +++ b/src/http/ngx_http_upstream.c Wed Jun 17 17:40:43 2020 +0900 > > @@ -4776,6 +4776,10 @@ > > return NGX_OK; > > } > > > > + if (r->cached == 1) { > > + return NGX_OK; > > + } > > + > > len = h->value.len; > > p = h->value.data; > > Thanks for the patch. > > The cache validity time as obtained from cached responses is used > while processing 304 responses during cache revalidation, so the > suggested change looks wrong to me. > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -- ------------------------------------- Sokichi TAKADA JOCDN Inc. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Mon Jun 22 10:37:49 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Jun 2020 13:37:49 +0300 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache In-Reply-To: References: <20200621211115.GA12747@mdounin.ru> Message-ID: <20200622103749.GC12747@mdounin.ru> Hello! On Mon, Jun 22, 2020 at 05:09:16PM +0900, Sokichi Takada wrote: > > The cache validity time as obtained from cached responses is used > > while processing 304 responses during cache revalidation, so the > > suggested change looks wrong to me. > > When processing 304 responses during cache revalidation, > ngx_http_upstream_process_accel_expires is called twice. > > 1st time, in "ngx_http_upstream_process_header" function. > src/http/ngx_http_upstream.c: 2387 rc = u->process_header(r); > # process_header = ngx_http_upstream_process_accel_expires > > This calculates the exact valid_sec value by x-accel-expires of upstream's > response, It doesn't use a value of the cache data. > Also, the r->cached is 0 at this time. > > 2nd time, in "ngx_http_upstream_process_header" -> > "ngx_http_upstream_test_next" -> "ngx_http_upstream_cache_send" function. > src/http/ngx_http_upstream.c: 2423 if > (ngx_http_upstream_test_next(r, u) == NGX_OK) -> > src/http/ngx_http_upstream.c: 2535 rc = > ngx_http_upstream_cache_send(r, u); -> > src/http/ngx_http_upstream.c: 1073 rc = u->process_header(r); > > This calculates unnecessary valid_sec value by x-accel-expires of the cache > data. > Also, this calculation can skip by this patch since the r->cached is 1 at > this time. > > Please look into ngx_http_upstream_test_next. > It keeps the valid_sec value of 1st time into "valid" variable at "2523 > valid = r->cache->valid_sec;". > After that, it "calls ngx_http_upstream_cache_send", then updates cache > data with the "valid" variable at "2560 r->cache->valid_sec = > valid;". Backend is not required to return cache control headers along with the 304 response. If it doesn't - nginx uses the headers returned in the cached response. -- Maxim Dounin http://mdounin.ru/ From ru at nginx.com Mon Jun 22 15:09:14 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 22 Jun 2020 18:09:14 +0300 Subject: Core: close pid file while writing it failed. In-Reply-To: References: Message-ID: <20200622150914.GC88174@lo0.su> On Thu, May 21, 2020 at 09:45:24PM +0800, Jim T wrote: > Hello! > > As far as I understand it, `ngx_create_pidfile` is a function that works > independently. There is no action to close the pid file externally, so we > need to close the pid file when the writing it failed. There are also > reports here https://github.com/nginx/nginx/pull/52. > > # HG changeset patch > # User Jinhua Tan <312841925 at qq.com> > # Date 1590068494 -28800 > # Thu May 21 21:41:34 2020 +0800 > # Node ID 6084ea4d9a4d2ae32f3fc4e2e3b9032ab0b71e30 > # Parent 3242f98298975e556a7e87130611ce84799fe935 > Core: close pid file while writing it failed. > > diff -r 3242f9829897 -r 6084ea4d9a4d src/core/ngx_cycle.c > --- a/src/core/ngx_cycle.c Wed May 20 12:24:05 2020 +0800 > +++ b/src/core/ngx_cycle.c Thu May 21 21:41:34 2020 +0800 > @@ -1036,6 +1036,12 @@ > len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; > > if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { > + > + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { > + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, > + ngx_close_file_n " \"%s\" failed", > file.name.data); > + } > + > return NGX_ERROR; > } > } > > Thank you! How's this instead? diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -1009,6 +1009,7 @@ ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) { size_t len; + ngx_int_t rc; ngx_uint_t create; ngx_file_t file; u_char pid[NGX_INT64_LEN + 2]; @@ -1033,11 +1034,13 @@ ngx_create_pidfile(ngx_str_t *name, ngx_ return NGX_ERROR; } + rc = NGX_OK; + if (!ngx_test_config) { len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { - return NGX_ERROR; + rc = NGX_ERROR; } } @@ -1046,7 +1049,7 @@ ngx_create_pidfile(ngx_str_t *name, ngx_ ngx_close_file_n " \"%s\" failed", file.name.data); } - return NGX_OK; + return rc; } From mdounin at mdounin.ru Mon Jun 22 16:19:45 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Jun 2020 16:19:45 +0000 Subject: [nginx] Large block sizes on Linux are now ignored (ticket #1168). Message-ID: details: https://hg.nginx.org/nginx/rev/0a04e5e4c40b branches: changeset: 7668:0a04e5e4c40b user: Maxim Dounin date: Mon Jun 22 18:02:58 2020 +0300 description: Large block sizes on Linux are now ignored (ticket #1168). NFS on Linux is known to report wsize as a block size (in both f_bsize and f_frsize, both in statfs() and statvfs()). On the other hand, typical file system block sizes on Linux (ext2/ext3/ext4, XFS) are limited to pagesize. (With FAT, block sizes can be at least up to 512k in extreme cases, but this doesn't really matter, see below.) To avoid too aggressive cache clearing on NFS volumes on Linux, block sizes larger than pagesize are now ignored. Note that it is safe to ignore large block sizes. Since 3899:e7cd13b7f759 (1.0.1) cache size is calculated based on fstat() st_blocks, and rounding to file system block size is preserved mostly for Windows. Note well that on other OSes valid block sizes seen are at least up to 65536. In particular, UFS on FreeBSD is known to work well with block and fragment sizes set to 65536. diffstat: src/os/unix/ngx_files.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diffs (29 lines): diff -r 1ece2ac2555a -r 0a04e5e4c40b src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c Mon Jun 15 20:17:16 2020 +0300 +++ b/src/os/unix/ngx_files.c Mon Jun 22 18:02:58 2020 +0300 @@ -875,6 +875,12 @@ ngx_fs_bsize(u_char *name) return 512; } +#if (NGX_LINUX) + if ((size_t) fs.f_bsize > ngx_pagesize) { + return 512; + } +#endif + return (size_t) fs.f_bsize; } @@ -893,6 +899,12 @@ ngx_fs_bsize(u_char *name) return 512; } +#if (NGX_LINUX) + if ((size_t) fs.f_frsize > ngx_pagesize) { + return 512; + } +#endif + return (size_t) fs.f_frsize; } From mdounin at mdounin.ru Mon Jun 22 16:19:48 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Jun 2020 16:19:48 +0000 Subject: [nginx] Too large st_blocks values are now ignored (ticket #157). Message-ID: details: https://hg.nginx.org/nginx/rev/52b34c3f89b4 branches: changeset: 7669:52b34c3f89b4 user: Maxim Dounin date: Mon Jun 22 18:02:59 2020 +0300 description: Too large st_blocks values are now ignored (ticket #157). With XFS, using "allocsize=64m" mount option results in large preallocation being reported in the st_blocks as returned by fstat() till the file is closed. This in turn results in incorrect cache size calculations and wrong clearing based on max_size. To avoid too aggressive cache clearing on such volumes, st_blocks values which result in sizes larger than st_size and eight blocks (an arbitrary limit) are no longer trusted, and we use st_size instead. The ngx_de_fs_size() counterpart is intentionally not modified, as it is used on closed files and hence not affected by this problem. diffstat: src/os/unix/ngx_files.h | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diffs (15 lines): diff -r 0a04e5e4c40b -r 52b34c3f89b4 src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h Mon Jun 22 18:02:58 2020 +0300 +++ b/src/os/unix/ngx_files.h Mon Jun 22 18:02:59 2020 +0300 @@ -185,7 +185,10 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_size(sb) (sb)->st_size -#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512) +#define ngx_file_fs_size(sb) \ + (((sb)->st_blocks * 512 > (sb)->st_size \ + && (sb)->st_blocks * 512 < (sb)->st_size + 8 * (sb)->st_blksize) \ + ? (sb)->st_blocks * 512 : (sb)->st_size) #define ngx_file_mtime(sb) (sb)->st_mtime #define ngx_file_uniq(sb) (sb)->st_ino From mdounin at mdounin.ru Mon Jun 22 16:19:52 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Jun 2020 16:19:52 +0000 Subject: [nginx] Cache: introduced min_free cache clearing. Message-ID: details: https://hg.nginx.org/nginx/rev/ccb5ff87ab3e branches: changeset: 7670:ccb5ff87ab3e user: Maxim Dounin date: Mon Jun 22 18:03:00 2020 +0300 description: Cache: introduced min_free cache clearing. Clearing cache based on free space left on a file system is expected to allow better disk utilization in some cases, notably when disk space might be also used for something other than nginx cache (including nginx own temporary files) and while loading cache (when cache size might be inaccurate for a while, effectively disabling max_size cache clearing). Based on a patch by Adam Bambuch. diffstat: src/http/ngx_http_cache.h | 1 + src/http/ngx_http_file_cache.c | 43 +++++++++++++++++++++++++++++++++++++++-- src/os/unix/ngx_files.c | 33 ++++++++++++++++++++++++++++++++ src/os/unix/ngx_files.h | 1 + src/os/win32/ngx_files.c | 13 ++++++++++++ src/os/win32/ngx_files.h | 1 + 6 files changed, 89 insertions(+), 3 deletions(-) diffs (199 lines): diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h Mon Jun 22 18:02:59 2020 +0300 +++ b/src/http/ngx_http_cache.h Mon Jun 22 18:03:00 2020 +0300 @@ -160,6 +160,7 @@ struct ngx_http_file_cache_s { ngx_path_t *path; + off_t min_free; off_t max_size; size_t bsize; diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c Mon Jun 22 18:02:59 2020 +0300 +++ b/src/http/ngx_http_file_cache.c Mon Jun 22 18:03:00 2020 +0300 @@ -1959,7 +1959,7 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; + off_t size, free; time_t wait; ngx_msec_t elapsed, next; ngx_uint_t count, watermark; @@ -1988,7 +1988,19 @@ ngx_http_file_cache_manager(void *data) size, count, (ngx_int_t) watermark); if (size < cache->max_size && count < watermark) { - break; + + if (!cache->min_free) { + break; + } + + free = ngx_fs_available(cache->path->name.data); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache free: %O", free); + + if (free > cache->min_free) { + break; + } } wait = ngx_http_file_cache_forced_expire(cache); @@ -2304,7 +2316,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t { char *confp = conf; - off_t max_size; + off_t max_size, min_free; u_char *last, *p; time_t inactive; ssize_t size; @@ -2341,6 +2353,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; + min_free = 0; value = cf->args->elts; @@ -2476,6 +2489,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t continue; } + if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) { + +#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS) + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + min_free = ngx_parse_offset(&s); + if (min_free < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid min_free value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "min_free is not supported " + "on this platform, ignored"); +#endif + + continue; + } + if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); @@ -2607,6 +2643,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t cache->inactive = inactive; cache->max_size = max_size; + cache->min_free = min_free; caches = (ngx_array_t *) (confp + cmd->offset); diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c Mon Jun 22 18:02:59 2020 +0300 +++ b/src/os/unix/ngx_files.c Mon Jun 22 18:03:00 2020 +0300 @@ -884,6 +884,19 @@ ngx_fs_bsize(u_char *name) return (size_t) fs.f_bsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_bsize; +} + #elif (NGX_HAVE_STATVFS) size_t @@ -908,6 +921,19 @@ ngx_fs_bsize(u_char *name) return (size_t) fs.f_frsize; } + +off_t +ngx_fs_available(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) fs.f_bavail * fs.f_frsize; +} + #else size_t @@ -916,4 +942,11 @@ ngx_fs_bsize(u_char *name) return 512; } + +off_t +ngx_fs_available(u_char *name) +{ + return NGX_MAX_OFF_T_VALUE; +} + #endif diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h Mon Jun 22 18:02:59 2020 +0300 +++ b/src/os/unix/ngx_files.h Mon Jun 22 18:03:00 2020 +0300 @@ -349,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); #if (NGX_HAVE_OPENAT) diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/os/win32/ngx_files.c --- a/src/os/win32/ngx_files.c Mon Jun 22 18:02:59 2020 +0300 +++ b/src/os/win32/ngx_files.c Mon Jun 22 18:03:00 2020 +0300 @@ -658,6 +658,19 @@ ngx_fs_bsize(u_char *name) } +off_t +ngx_fs_available(u_char *name) +{ + ULARGE_INTEGER navail; + + if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) { + return NGX_MAX_OFF_T_VALUE; + } + + return (off_t) navail.QuadPart; +} + + static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, size_t len) { diff -r 52b34c3f89b4 -r ccb5ff87ab3e src/os/win32/ngx_files.h --- a/src/os/win32/ngx_files.h Mon Jun 22 18:02:59 2020 +0300 +++ b/src/os/win32/ngx_files.h Mon Jun 22 18:03:00 2020 +0300 @@ -259,6 +259,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #define ngx_directio_off_n "ngx_directio_off_n" size_t ngx_fs_bsize(u_char *name); +off_t ngx_fs_available(u_char *name); #define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE) From takada at jocdn.co.jp Wed Jun 24 11:32:18 2020 From: takada at jocdn.co.jp (Sokichi Takada) Date: Wed, 24 Jun 2020 20:32:18 +0900 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache In-Reply-To: <20200622103749.GC12747@mdounin.ru> References: <20200621211115.GA12747@mdounin.ru> <20200622103749.GC12747@mdounin.ru> Message-ID: Hello! In my case, the backend returns x-accel-expires with 304 responses every time. nginx calculates valid_sec by "ngx_http_upstream_process_accel_expires" for any revalidate or HIT responses, thus to get the wrong valid_sec value in header_filter/log hook handler. This patch has no impact to every response results, and to be able to get TRUE valid_sec value in the hook handlers. --- TAKADA Sokichi On Mon, Jun 22, 2020 at 7:37 PM Maxim Dounin wrote: > Hello! > > On Mon, Jun 22, 2020 at 05:09:16PM +0900, Sokichi Takada wrote: > > > > The cache validity time as obtained from cached responses is used > > > while processing 304 responses during cache revalidation, so the > > > suggested change looks wrong to me. > > > > When processing 304 responses during cache revalidation, > > ngx_http_upstream_process_accel_expires is called twice. > > > > 1st time, in "ngx_http_upstream_process_header" function. > > src/http/ngx_http_upstream.c: 2387 rc = u->process_header(r); > > # process_header = ngx_http_upstream_process_accel_expires > > > > This calculates the exact valid_sec value by x-accel-expires of > upstream's > > response, It doesn't use a value of the cache data. > > Also, the r->cached is 0 at this time. > > > > 2nd time, in "ngx_http_upstream_process_header" -> > > "ngx_http_upstream_test_next" -> "ngx_http_upstream_cache_send" function. > > src/http/ngx_http_upstream.c: 2423 if > > (ngx_http_upstream_test_next(r, u) == NGX_OK) -> > > src/http/ngx_http_upstream.c: 2535 rc = > > ngx_http_upstream_cache_send(r, u); -> > > src/http/ngx_http_upstream.c: 1073 rc = u->process_header(r); > > > > This calculates unnecessary valid_sec value by x-accel-expires of the > cache > > data. > > Also, this calculation can skip by this patch since the r->cached is 1 at > > this time. > > > > Please look into ngx_http_upstream_test_next. > > It keeps the valid_sec value of 1st time into "valid" variable at "2523 > > valid = r->cache->valid_sec;". > > After that, it "calls ngx_http_upstream_cache_send", then updates cache > > data with the "valid" variable at "2560 r->cache->valid_sec = > > valid;". > > Backend is not required to return cache control headers along with > the 304 response. If it doesn't - nginx uses the headers returned > in the cached response. > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -- ------------------------------------- Sokichi TAKADA JOCDN Inc. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Thu Jun 25 08:56:43 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 25 Jun 2020 11:56:43 +0300 Subject: [PATCH] skip apply "ngx_http_upstream_process_accel_expires" when a request responeded by cache In-Reply-To: References: <20200621211115.GA12747@mdounin.ru> <20200622103749.GC12747@mdounin.ru> Message-ID: <20200625085643.GH12747@mdounin.ru> Hello! On Wed, Jun 24, 2020 at 08:32:18PM +0900, Sokichi Takada wrote: > In my case, the backend returns x-accel-expires with 304 responses every > time. > > nginx calculates valid_sec by "ngx_http_upstream_process_accel_expires" for > any revalidate or HIT responses, thus to get the wrong valid_sec value in > header_filter/log hook handler. > This patch has no impact to every response results, and to be able to get > TRUE valid_sec value in the hook handlers. No doubt the patch is working for you. But the patch breaks other valid use cases. On the other hand, the only thing it expected to do is to set the valid_sec field, which is unused by nginx itself in you particular use case, to something you think is "TRUE" for your particular use case. Again, thank you for the patch, but no. -- Maxim Dounin http://mdounin.ru/ From alexander.borisov at nginx.com Thu Jun 25 10:11:30 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 25 Jun 2020 10:11:30 +0000 Subject: [njs] Parser: fixed broken object literals parsing. Message-ID: details: https://hg.nginx.org/njs/rev/d692284e0b9f branches: changeset: 1439:d692284e0b9f user: Alexander Borisov date: Thu Jun 25 13:10:03 2020 +0300 description: Parser: fixed broken object literals parsing. diffstat: src/njs_parser.c | 9 ++++++--- src/test/njs_unit_test.c | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diffs (77 lines): diff -r 7d24976ced90 -r d692284e0b9f src/njs_parser.c --- a/src/njs_parser.c Fri Jun 19 19:48:13 2020 +0300 +++ b/src/njs_parser.c Thu Jun 25 13:10:03 2020 +0300 @@ -1694,7 +1694,7 @@ njs_parser_object_literal(njs_parser_t * njs_parser_next(parser, njs_parser_property_definition_list); - return njs_parser_after(parser, current, node, 0, + return njs_parser_after(parser, current, node, 1, njs_parser_object_literal_after); } @@ -1733,7 +1733,7 @@ njs_parser_property_definition_list(njs_ { njs_parser_next(parser, njs_parser_property_definition); - return njs_parser_after(parser, current, parser->target, 0, + return njs_parser_after(parser, current, parser->target, 1, njs_parser_property_definition_list_after); } @@ -1750,7 +1750,7 @@ njs_parser_property_definition_list_afte njs_parser_next(parser, njs_parser_property_definition); - return njs_parser_after(parser, current, parser->target, 0, + return njs_parser_after(parser, current, parser->target, 1, njs_parser_property_definition_list_after); } @@ -1866,6 +1866,9 @@ njs_parser_property_definition(njs_parse temp = parser->target; switch (token->type) { + case NJS_TOKEN_CLOSE_BRACE: + return njs_parser_stack_pop(parser); + /* PropertyName */ case NJS_TOKEN_STRING: case NJS_TOKEN_ESCAPE_STRING: diff -r 7d24976ced90 -r d692284e0b9f src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Jun 19 19:48:13 2020 +0300 +++ b/src/test/njs_unit_test.c Thu Jun 25 13:10:03 2020 +0300 @@ -11713,7 +11713,7 @@ static njs_unit_test_t njs_test[] = njs_str("RangeError: Maximum call stack size exceeded") }, { njs_str("new Function(\"{[\".repeat(2**13));"), - njs_str("SyntaxError: Unexpected token \")\" in runtime:1") }, + njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") }, { njs_str("new Function(\"{;\".repeat(2**13));"), njs_str("SyntaxError: Unexpected token \")\" in runtime:1") }, @@ -17022,6 +17022,24 @@ static njs_unit_test_t njs_test[] = { njs_str("object?."), njs_str("SyntaxError: Unexpected end of input in 1") }, + + { njs_str("`${{a: 1, b}}`"), + njs_str("ReferenceError: \"b\" is not defined in 1") }, + + { njs_str("`${{a: 1, b:}}`"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("`${{a: 1, b:,}}`"), + njs_str("SyntaxError: Unexpected token \",\" in 1") }, + + { njs_str("`${{a: 1, b: 2,}}`"), + njs_str("[object Object]") }, + + { njs_str("`${{a: 1,, b: 2}}`"), + njs_str("SyntaxError: Unexpected token \",\" in 1") }, + + { njs_str("`${{f(){-} - {}}`"), + njs_str("SyntaxError: Unexpected token \"}\" in 1") }, }; From alexander.borisov at nginx.com Thu Jun 25 10:11:32 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Thu, 25 Jun 2020 10:11:32 +0000 Subject: [njs] Parser: fixed broken for expressions parsing. Message-ID: details: https://hg.nginx.org/njs/rev/fac632b520fa branches: changeset: 1440:fac632b520fa user: Alexander Borisov date: Thu Jun 25 13:10:04 2020 +0300 description: Parser: fixed broken for expressions parsing. diffstat: src/njs_parser.c | 2 +- src/test/njs_unit_test.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diffs (25 lines): diff -r d692284e0b9f -r fac632b520fa src/njs_parser.c --- a/src/njs_parser.c Thu Jun 25 13:10:03 2020 +0300 +++ b/src/njs_parser.c Thu Jun 25 13:10:04 2020 +0300 @@ -5218,7 +5218,7 @@ njs_parser_iteration_statement_for_map(n njs_parser_next(parser, njs_parser_expression); - return njs_parser_after(parser, current, NULL, 0, + return njs_parser_after(parser, current, NULL, 1, njs_parser_for_expression); } diff -r d692284e0b9f -r fac632b520fa src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Jun 25 13:10:03 2020 +0300 +++ b/src/test/njs_unit_test.c Thu Jun 25 13:10:04 2020 +0300 @@ -17040,6 +17040,9 @@ static njs_unit_test_t njs_test[] = { njs_str("`${{f(){-} - {}}`"), njs_str("SyntaxError: Unexpected token \"}\" in 1") }, + + { njs_str("for (;1-;) {}"), + njs_str("SyntaxError: Unexpected token \";\" in 1") }, }; From ru at nginx.com Fri Jun 26 10:13:52 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Fri, 26 Jun 2020 10:13:52 +0000 Subject: [nginx] Fixed potential leak of temp pool. Message-ID: details: https://hg.nginx.org/nginx/rev/7e0719fb528b branches: changeset: 7671:7e0719fb528b user: Eran Kornblau date: Mon Jun 15 03:58:31 2020 -0400 description: Fixed potential leak of temp pool. In case ngx_hash_add_key() fails, need to goto failed instead of returning, so that temp_pool will be destoryed. diffstat: src/http/ngx_http.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (20 lines): diff -r ccb5ff87ab3e -r 7e0719fb528b src/http/ngx_http.c --- a/src/http/ngx_http.c Mon Jun 22 18:03:00 2020 +0300 +++ b/src/http/ngx_http.c Mon Jun 15 03:58:31 2020 -0400 @@ -1469,14 +1469,14 @@ ngx_http_server_names(ngx_conf_t *cf, ng NGX_HASH_WILDCARD_KEY); if (rc == NGX_ERROR) { - return NGX_ERROR; + goto failed; } if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid server name or wildcard \"%V\" on %V", &name[n].name, &addr->opt.addr_text); - return NGX_ERROR; + goto failed; } if (rc == NGX_BUSY) { From ru at nginx.com Fri Jun 26 16:38:22 2020 From: ru at nginx.com (Ruslan Ermilov) Date: Fri, 26 Jun 2020 19:38:22 +0300 Subject: [PATCH] Fixed potential leak of temp pool. In-Reply-To: References: Message-ID: <20200626163822.GH75058@lo0.su> On Mon, Jun 15, 2020 at 08:48:41AM +0000, Eran Kornblau wrote: > Hi > > Something I noticed today while looking at the code, it probably won't matter to anyone ever... > But just sending for the sake of perfection :) > > Thanks! > > Eran Committed, thanks! https://hg.nginx.org/nginx/rev/7e0719fb528b > # HG changeset patch > # User erankor > # Date 1592207911 14400 > # Mon Jun 15 03:58:31 2020 -0400 > # Node ID 7037b11208c1be350c399bf0917b439fb5356d3b > # Parent cb27bda9557fede50b531a0b3b4db98b38cc937a > Fixed potential leak of temp pool. > > In case ngx_hash_add_key fails, need to goto failed instead of returning, so > that temp_pool will be destoryed. > > diff -r cb27bda9557f -r 7037b11208c1 src/http/ngx_http.c > --- a/src/http/ngx_http.c Mon Aug 07 06:10:34 2017 -0400 > +++ b/src/http/ngx_http.c Mon Jun 15 03:58:31 2020 -0400 > @@ -1466,14 +1466,14 @@ > NGX_HASH_WILDCARD_KEY); > > if (rc == NGX_ERROR) { > - return NGX_ERROR; > + goto failed; > } > > if (rc == NGX_DECLINED) { > ngx_log_error(NGX_LOG_EMERG, cf->log, 0, > "invalid server name or wildcard \"%V\" on %s", > &name[n].name, addr->opt.addr); > - return NGX_ERROR; > + goto failed; > } > > if (rc == NGX_BUSY) { > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Ruslan Ermilov Assume stupidity not malice From mdounin at mdounin.ru Mon Jun 29 21:15:35 2020 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 29 Jun 2020 21:15:35 +0000 Subject: [nginx] SSL: fixed unexpected certificate requests (ticket #2008). Message-ID: details: https://hg.nginx.org/nginx/rev/3dcb1aba894a branches: changeset: 7672:3dcb1aba894a user: Maxim Dounin date: Mon Jun 29 17:15:51 2020 +0300 description: SSL: fixed unexpected certificate requests (ticket #2008). Using SSL_CTX_set_verify(SSL_VERIFY_PEER) implies that OpenSSL will send a certificate request during an SSL handshake, leading to unexpected certificate requests from browsers as long as there are any client certificates installed. Given that ngx_ssl_trusted_certificate() is called unconditionally by the ngx_http_ssl_module, this affected all HTTPS servers. Broken by 699f6e55bbb4 (not released yet). Fix is to set verify callback in the ngx_ssl_trusted_certificate() function without changing the verify mode. diffstat: src/event/ngx_event_openssl.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (13 lines): diff -r 7e0719fb528b -r 3dcb1aba894a src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Mon Jun 15 03:58:31 2020 -0400 +++ b/src/event/ngx_event_openssl.c Mon Jun 29 17:15:51 2020 +0300 @@ -920,7 +920,8 @@ ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) { - SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback); + SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx), + ngx_ssl_verify_callback); SSL_CTX_set_verify_depth(ssl->ctx, depth); From alexander.borisov at nginx.com Tue Jun 30 15:22:59 2020 From: alexander.borisov at nginx.com (Alexander Borisov) Date: Tue, 30 Jun 2020 15:22:59 +0000 Subject: [njs] Fixed index generation for global objects. Message-ID: details: https://hg.nginx.org/njs/rev/52dd845c0a36 branches: changeset: 1441:52dd845c0a36 user: Alexander Borisov date: Tue Jun 30 18:22:18 2020 +0300 description: Fixed index generation for global objects. In c75a8fc6d534 "GLOBAL GET" instruction was introduced to handle unresolved references. The issue was that the "GLOBAL GET" instruction erroneously used the assignment variable index as a destination index. The result was that a variable was assigned the retval of a "GLOBAL GET" instruction. The fix is to use a separate temporary index for "GLOBAL GET". This closes #289 issue on GitHub. diffstat: src/njs_generator.c | 2 +- src/test/njs_unit_test.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletions(-) diffs (28 lines): diff -r fac632b520fa -r 52dd845c0a36 src/njs_generator.c --- a/src/njs_generator.c Thu Jun 25 13:10:04 2020 +0300 +++ b/src/njs_generator.c Tue Jun 30 18:22:18 2020 +0300 @@ -3384,7 +3384,7 @@ njs_generate_global_reference(njs_vm_t * njs_vmcode_prop_get_t *prop_get; const njs_lexer_entry_t *lex_entry; - index = njs_generate_dest_index(vm, generator, node); + index = njs_generate_temp_index_get(vm, generator, node); if (njs_slow_path(index == NJS_INDEX_ERROR)) { return NJS_ERROR; } diff -r fac632b520fa -r 52dd845c0a36 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Thu Jun 25 13:10:04 2020 +0300 +++ b/src/test/njs_unit_test.c Tue Jun 30 18:22:18 2020 +0300 @@ -17043,6 +17043,12 @@ static njs_unit_test_t njs_test[] = { njs_str("for (;1-;) {}"), njs_str("SyntaxError: Unexpected token \";\" in 1") }, + + { njs_str("var str = String(str); str"), + njs_str("undefined") }, + + { njs_str("var t = \"123\"; t = parseInt(t); t"), + njs_str("123") }, }; From xeioex at nginx.com Tue Jun 30 15:36:51 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 30 Jun 2020 15:36:51 +0000 Subject: [njs] Adding Symbol support for backtraces. Message-ID: details: https://hg.nginx.org/njs/rev/85c1b6ba326b branches: changeset: 1442:85c1b6ba326b user: Dmitry Volyntsev date: Tue Jun 30 15:33:58 2020 +0000 description: Adding Symbol support for backtraces. diffstat: src/njs_builtin.c | 21 ++++++++++++++++----- src/njs_json.c | 4 ++-- src/njs_object.h | 2 +- src/njs_string.c | 2 +- src/njs_symbol.c | 36 ++++++++++++++++++++++++++---------- src/njs_symbol.h | 2 +- 6 files changed, 47 insertions(+), 20 deletions(-) diffs (165 lines): diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_builtin.c --- a/src/njs_builtin.c Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_builtin.c Tue Jun 30 15:33:58 2020 +0000 @@ -396,6 +396,7 @@ njs_builtin_traverse(njs_vm_t *vm, njs_t u_char *p, *start, *end; njs_int_t ret, n; njs_str_t name; + njs_value_t key; njs_function_t *func; njs_object_prop_t *prop; njs_lvlhsh_query_t lhq; @@ -430,7 +431,21 @@ njs_builtin_traverse(njs_vm_t *vm, njs_t end = buf + sizeof(buf); do { - njs_string_get(&path[n]->prop->name, &name); + key = path[n]->prop->name; + + if (njs_slow_path(njs_is_symbol(&key))) { + ret = njs_symbol_to_string(vm, &key, &key, 1); + if (njs_slow_path(ret != NJS_OK)) { + name = njs_str_value("#BROKEN_KEY"); + } + + } else { + if (p != buf) { + *p++ = '.'; + } + } + + njs_string_get(&key, &name); if (njs_slow_path((p + name.length + 1) > end)) { njs_type_error(vm, "njs_builtin_traverse() key is too long"); @@ -439,10 +454,6 @@ njs_builtin_traverse(njs_vm_t *vm, njs_t p = njs_cpymem(p, name.start, name.length); - if (n != 0) { - *p++ = '.'; - } - } while (n-- > 0); if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) { diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_json.c --- a/src/njs_json.c Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_json.c Tue Jun 30 15:33:58 2020 +0000 @@ -1856,7 +1856,7 @@ njs_dump_terminal(njs_json_stringify_t * case NJS_OBJECT_SYMBOL: value = njs_object_value(value); - ret = njs_symbol_to_string(stringify->vm, &str_val, value); + ret = njs_symbol_to_string(stringify->vm, &str_val, value, 0); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } @@ -1867,7 +1867,7 @@ njs_dump_terminal(njs_json_stringify_t * break; case NJS_SYMBOL: - ret = njs_symbol_to_string(stringify->vm, &str_val, value); + ret = njs_symbol_to_string(stringify->vm, &str_val, value, 0); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_object.h --- a/src/njs_object.h Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_object.h Tue Jun 30 15:33:58 2020 +0000 @@ -213,7 +213,7 @@ njs_key_string_get(njs_vm_t *vm, njs_val njs_int_t ret; if (njs_slow_path(njs_is_symbol(key))) { - ret = njs_symbol_to_string(vm, key, key); + ret = njs_symbol_to_string(vm, key, key, 0); if (njs_slow_path(ret != NJS_OK)) { return ret; } diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_string.c --- a/src/njs_string.c Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_string.c Tue Jun 30 15:33:58 2020 +0000 @@ -543,7 +543,7 @@ njs_string_constructor(njs_vm_t *vm, njs if (njs_slow_path(!njs_is_string(value))) { if (!vm->top_frame->ctor && njs_is_symbol(value)) { - return njs_symbol_to_string(vm, &vm->retval, value); + return njs_symbol_to_string(vm, &vm->retval, value, 0); } ret = njs_value_to_string(vm, value, value); diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_symbol.c --- a/src/njs_symbol.c Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_symbol.c Tue Jun 30 15:33:58 2020 +0000 @@ -55,7 +55,8 @@ static const njs_value_t *njs_symbol_na njs_int_t -njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *value) +njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *value, + njs_bool_t as_name) { u_char *start; const njs_value_t *name; @@ -78,17 +79,32 @@ njs_symbol_to_string(njs_vm_t *vm, njs_v } (void) njs_string_prop(&string, name); - string.length += njs_length("Symbol()"); + + if (as_name) { + string.length += njs_length("[]"); + + start = njs_string_alloc(vm, dst, string.size + 2, string.length); + if (njs_slow_path(start == NULL)) { + return NJS_ERROR; + } + + start = njs_cpymem(start, "[", 1); + start = njs_cpymem(start, string.start, string.size); + *start = ']'; - start = njs_string_alloc(vm, dst, string.size + 8, string.length); - if (njs_slow_path(start == NULL)) { - return NJS_ERROR; + } else { + string.length += njs_length("Symbol()"); + + start = njs_string_alloc(vm, dst, string.size + 8, string.length); + if (njs_slow_path(start == NULL)) { + return NJS_ERROR; + } + + start = njs_cpymem(start, "Symbol(", 7); + start = njs_cpymem(start, string.start, string.size); + *start = ')'; } - start = njs_cpymem(start, "Symbol(", 7); - start = njs_cpymem(start, string.start, string.size); - *start = ')'; - return NJS_OK; } @@ -328,7 +344,7 @@ njs_symbol_prototype_to_string(njs_vm_t return ret; } - return njs_symbol_to_string(vm, &vm->retval, &vm->retval); + return njs_symbol_to_string(vm, &vm->retval, &vm->retval, 0); } diff -r 52dd845c0a36 -r 85c1b6ba326b src/njs_symbol.h --- a/src/njs_symbol.h Tue Jun 30 18:22:18 2020 +0300 +++ b/src/njs_symbol.h Tue Jun 30 15:33:58 2020 +0000 @@ -8,7 +8,7 @@ #define _NJS_SYMBOL_H_INCLUDED_ njs_int_t njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst, - const njs_value_t *value); + const njs_value_t *value, njs_bool_t as_name); extern const njs_object_type_init_t njs_symbol_type_init; From xeioex at nginx.com Tue Jun 30 15:36:53 2020 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 30 Jun 2020 15:36:53 +0000 Subject: [njs] Introduced StringIndexOf(). Message-ID: details: https://hg.nginx.org/njs/rev/e8a941b394a3 branches: changeset: 1443:e8a941b394a3 user: Dmitry Volyntsev date: Tue Jun 30 15:36:31 2020 +0000 description: Introduced StringIndexOf(). diffstat: src/njs_string.c | 167 +++++++++++++++++++++++++++--------------------------- 1 files changed, 84 insertions(+), 83 deletions(-) diffs (186 lines): diff -r 85c1b6ba326b -r e8a941b394a3 src/njs_string.c --- a/src/njs_string.c Tue Jun 30 15:33:58 2020 +0000 +++ b/src/njs_string.c Tue Jun 30 15:36:31 2020 +0000 @@ -1981,98 +1981,99 @@ range_error: } +static int64_t +njs_string_index_of(njs_string_prop_t *string, njs_string_prop_t *search, + size_t from) +{ + size_t index, length, search_length; + const u_char *p, *end; + + length = (string->length == 0) ? string->size : string->length; + + if (njs_slow_path(search->size == 0)) { + return (from < length) ? from : length; + } + + index = from; + search_length = (search->length == 0) ? search->size : search->length; + + if (length - index >= search_length) { + end = string->start + string->size; + + if (string->size == length) { + /* Byte or ASCII string. */ + + end -= (search->size - 1); + + for (p = string->start + index; p < end; p++) { + if (memcmp(p, search->start, search->size) == 0) { + return index; + } + + index++; + } + + } else { + /* UTF-8 string. */ + + p = njs_string_offset(string->start, end, index); + end -= search->size - 1; + + while (p < end) { + if (memcmp(p, search->start, search->size) == 0) { + return index; + } + + index++; + p = njs_utf8_next(p, end); + } + } + } + + return -1; +} + + static njs_int_t njs_string_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - int64_t index, length, search_length; + int64_t from; njs_int_t ret; - njs_value_t *value; - const u_char *p, *end; - njs_string_prop_t string, search; - - ret = njs_string_object_validate(vm, njs_arg(args, nargs, 0)); + njs_value_t *this, *search, *pos, search_lvalue, pos_lvalue; + njs_string_prop_t string, s; + + this = njs_argument(args, 0); + + if (njs_slow_path(njs_is_null_or_undefined(this))) { + njs_type_error(vm, "cannot convert \"%s\"to object", + njs_type_string(this->type)); + return NJS_ERROR; + } + + ret = njs_value_to_string(vm, this, this); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + search = njs_lvalue_arg(&search_lvalue, args, nargs, 1); + ret = njs_value_to_string(vm, search, search); if (njs_slow_path(ret != NJS_OK)) { return ret; } - if (nargs > 1) { - length = njs_string_prop(&string, njs_argument(args, 0)); - - value = njs_argument(args, 1); - - if (njs_slow_path(!njs_is_string(value))) { - ret = njs_value_to_string(vm, value, value); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - } - - search_length = njs_string_prop(&search, value); - - index = 0; - - if (nargs > 2) { - value = njs_argument(args, 2); - - if (njs_slow_path(!njs_is_number(value))) { - ret = njs_value_to_integer(vm, value, &index); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - } else { - index = njs_number_to_integer(njs_number(value)); - } - - if (index < 0) { - index = 0; - } - } - - if (length - index >= search_length) { - end = string.start + string.size; - - if (string.size == (size_t) length) { - /* Byte or ASCII string. */ - - end -= (search.size - 1); - - for (p = string.start + index; p < end; p++) { - if (memcmp(p, search.start, search.size) == 0) { - goto done; - } - - index++; - } - - } else { - /* UTF-8 string. */ - - p = njs_string_offset(string.start, end, index); - end -= search.size - 1; - - while (p < end) { - if (memcmp(p, search.start, search.size) == 0) { - goto done; - } - - index++; - p = njs_utf8_next(p, end); - } - } - - } else if (search.size == 0) { - index = length; - goto done; - } - } - - index = -1; - -done: - - njs_set_number(&vm->retval, index); + pos = njs_lvalue_arg(&pos_lvalue, args, nargs, 2); + ret = njs_value_to_integer(vm, pos, &from); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + (void) njs_string_prop(&string, this); + (void) njs_string_prop(&s, search); + + from = njs_min(njs_max(from, 0), (int64_t) string.length); + + njs_set_number(&vm->retval, njs_string_index_of(&string, &s, from)); return NJS_OK; } From dionnaglaze at google.com Tue Jun 30 23:09:16 2020 From: dionnaglaze at google.com (Dionna Amalie Glaze) Date: Tue, 30 Jun 2020 16:09:16 -0700 Subject: [nginx-test] Allow some syslog message to arrive in either order Message-ID: # HG changeset patch # User Dionna Glaze # Date 1593542175 25200 # Tue Jun 30 11:36:15 2020 -0700 # Node ID a2a00a127689c64d21842d2aba7f1dc53e06b095 # Parent f55d25e08b3edaab6f3a30a000ac486334994978 Allow some syslog message to arrive in either order This test flakes occasionally with good,work arriving as work,good. diff --git a/syslog.t b/syslog.t --- a/syslog.t +++ b/syslog.t *@@ -220,7 +220,7 @@ http_get('/if/work?logme=yes');* get_syslog('/a'); -like($t->read_file('s_if.log'), qr/good:404.*work:404/s, 'syslog if success'); +like($t->read_file('s_if.log'), qr/*(*good:404.*work:404 *)|(work:404.*good:404)*/s, 'syslog if success'); unlike($t->read_file('s_if.log'), qr/(if:|empty:|zero:)404/, 'syslog if fail'); like(get_syslog('/nohostname'), -- -Dionna Glaze, PhD (she/her) -------------- next part -------------- An HTML attachment was scrubbed... URL: