From a1189cfb6238adcb8e108769109663d8620585b5 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Tue, 19 Nov 2019 15:44:12 +0100 Subject: [PATCH] Add validation for single statement lexical declarations (#3326) This patch fixes #3275 and fixes #3276. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/parser/js/js-parser-statm.c | 30 ++++++++++++++ jerry-core/parser/js/js-parser-util.c | 4 ++ jerry-core/parser/js/js-parser.h | 1 + tests/jerry/es2015/let12.js | 41 +++++++++++++++++++ .../regression-test-issue-3151-function.js | 0 .../regression-test-issue-3276.js} | 2 +- .../jerry/fail/regresssion-test-issue-3275.js | 15 +++++++ 7 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/jerry/es2015/let12.js rename tests/jerry/{ => es5.1}/regression-test-issue-3151-function.js (100%) rename tests/jerry/{es2015/regression-test-issue-3151-class.js => fail/regression-test-issue-3276.js} (95%) create mode 100644 tests/jerry/fail/regresssion-test-issue-3275.js diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index c5cc19ff1..31b5d7fea 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -477,6 +477,21 @@ parser_pop_block_context (parser_context_t *context_p) /**< context */ parser_stack_iterator_init (context_p, &context_p->last_statement); } /* parser_pop_block_context */ +/** + * Validate lexical context for a declaration. + */ +static void +parser_validate_lexical_context (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_LET + || context_p->token.type == LEXER_KEYW_CONST + || context_p->token.type == LEXER_KEYW_CLASS); + + if (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } +} /* parser_validate_lexical_context */ #endif /* ENABLED (JERRY_ES2015) */ /** @@ -491,6 +506,11 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) uint8_t declaration_type = context_p->token.type; + + if (declaration_type != LEXER_KEYW_VAR) + { + parser_validate_lexical_context (context_p); + } #endif /* ENABLED (JERRY_ES2015) */ while (true) @@ -612,6 +632,15 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION); +#if ENABLED (JERRY_ES2015) + if ((parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) + && !(context_p->stack_top_uint8 == PARSER_STATEMENT_IF + || context_p->stack_top_uint8 == PARSER_STATEMENT_ELSE)) + { + parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); + } +#endif /* ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) parser_line_counter_t debugger_line = context_p->token.line; parser_line_counter_t debugger_column = context_p->token.column; @@ -2636,6 +2665,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { + parser_validate_lexical_context (context_p); parser_parse_class (context_p, true); goto consume_last_statement; } diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index a2128f615..5bf38a291 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -1089,6 +1089,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Local variable is redeclared."; } + case PARSER_ERR_LEXICAL_SINGLE_STATEMENT: + { + return "Lexical declaration cannot appear in a single-statement context."; + } case PARSER_ERR_MISSING_ASSIGN_AFTER_CONST: { return "Value assignment is expected after a const declaration."; diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index ae4feeff5..c96fc8352 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -115,6 +115,7 @@ typedef enum PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */ #if ENABLED (JERRY_ES2015) PARSER_ERR_VARIABLE_REDECLARED, /**< a variable redeclared */ + PARSER_ERR_LEXICAL_SINGLE_STATEMENT, /**< lexical variable in single statement context */ PARSER_ERR_MISSING_ASSIGN_AFTER_CONST, /**< an assignment is required after a const declaration */ PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */ diff --git a/tests/jerry/es2015/let12.js b/tests/jerry/es2015/let12.js new file mode 100644 index 000000000..2ef22d85e --- /dev/null +++ b/tests/jerry/es2015/let12.js @@ -0,0 +1,41 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +checkSyntax ("if (5) let a;"); +checkSyntax ("if (5) const a;"); +checkSyntax ("if (0) {} else let a;"); +checkSyntax ("if (0) {} else const a;"); +checkSyntax ("while (5) let a;"); +checkSyntax ("while (5) const a;"); +checkSyntax ("do let a; while (5)"); +checkSyntax ("do const a; while (5)"); +checkSyntax ("for (a in b) let c;"); +checkSyntax ("for (a in b) const c;"); +checkSyntax ("for (a of b) let c;"); +checkSyntax ("for (a of b) const c;"); +checkSyntax ("for (;;) let c;"); +checkSyntax ("for (;;) const c;"); +checkSyntax ("with ({}) let c;"); +checkSyntax ("with ({}) const c;"); +checkSyntax ("a: let c;"); +checkSyntax ("a: const c;"); diff --git a/tests/jerry/regression-test-issue-3151-function.js b/tests/jerry/es5.1/regression-test-issue-3151-function.js similarity index 100% rename from tests/jerry/regression-test-issue-3151-function.js rename to tests/jerry/es5.1/regression-test-issue-3151-function.js diff --git a/tests/jerry/es2015/regression-test-issue-3151-class.js b/tests/jerry/fail/regression-test-issue-3276.js similarity index 95% rename from tests/jerry/es2015/regression-test-issue-3151-class.js rename to tests/jerry/fail/regression-test-issue-3276.js index 4e8644805..5c25208ef 100644 --- a/tests/jerry/es2015/regression-test-issue-3151-class.js +++ b/tests/jerry/fail/regression-test-issue-3276.js @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -do class $ { } while (0); +with ({ }) class ${ $( ) { $ } } diff --git a/tests/jerry/fail/regresssion-test-issue-3275.js b/tests/jerry/fail/regresssion-test-issue-3275.js new file mode 100644 index 000000000..99f10326f --- /dev/null +++ b/tests/jerry/fail/regresssion-test-issue-3275.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +for ( i in this ) class ${ } eval ( )