From 4735570b3139574133dd47ea085b6ad31ec787b1 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 28 Oct 2014 13:38:13 +0400 Subject: [PATCH] Add SyntaxErrors on parsing ObjectDeclarations. --- src/libintstructs/lp-string.h | 2 +- src/libintstructs/stack.h | 5 + src/libjsparser/lexer.c | 3 +- src/libjsparser/parser.c | 288 ++++++++++++++++-------- tests/jerry/fail/255/object_get_data.js | 15 ++ tests/jerry/fail/255/object_get_get.js | 15 ++ tests/jerry/object_literal-2.js | 17 ++ 7 files changed, 253 insertions(+), 92 deletions(-) create mode 100644 tests/jerry/fail/255/object_get_data.js create mode 100644 tests/jerry/fail/255/object_get_get.js create mode 100644 tests/jerry/object_literal-2.js diff --git a/src/libintstructs/lp-string.h b/src/libintstructs/lp-string.h index 371abf448..d4486439e 100644 --- a/src/libintstructs/lp-string.h +++ b/src/libintstructs/lp-string.h @@ -21,7 +21,7 @@ /* Length-prefixed or "pascal" string. */ typedef struct { - ecma_char_t *str; + const ecma_char_t *str; ecma_length_t length; } lp_string; diff --git a/src/libintstructs/stack.h b/src/libintstructs/stack.h index 8c73a833f..fbc257060 100644 --- a/src/libintstructs/stack.h +++ b/src/libintstructs/stack.h @@ -218,6 +218,11 @@ do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, #define STACK_DECR_ELEMENT(NAME, I) \ do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, I) - 1)); } while (0) +#define STACK_ITERATE(NAME, FUNC, FROM) \ +do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \ + FUNC (STACK_ELEMENT (NAME, i)); \ +} } while (0) + #define STACK_ITERATE_VARG(NAME, FUNC, FROM, ...) \ do { for (NAME##_stack_data_type i = FROM; i < NAME.current; i++) { \ FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__); \ diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index e304c64e8..d28a52532 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -177,7 +177,7 @@ add_current_token_to_string_cache (void) } __strncpy ((char *) (strings_cache + strings_cache_used_size), token_start, res.length); res.str = strings_cache + strings_cache_used_size; - res.str[res.length] = '\0'; + (strings_cache + strings_cache_used_size)[res.length] = '\0'; strings_cache_used_size = (size_t) (((size_t) res.length + 1) * sizeof (ecma_char_t) + strings_cache_used_size); return res; } @@ -788,6 +788,7 @@ parse_number (void) c = LA (0); if (is_fp && c == '.') { + FIXME (/* This is wrong: 1..toString (). */) PARSE_ERROR ("Integer literal shall not contain more than one dot character", buffer - buffer_start); } if (is_exp && (c == 'e' || c == 'E')) diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index c4fc4c4e1..82ce2af4a 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -50,6 +50,29 @@ typedef struct } intrinsic_dumper; +typedef enum +{ + PROP_DATA, + PROP_SET, + PROP_GET, + VARG +} +prop_type; + +typedef struct +{ + lp_string str; + bool was_num; +} +allocatable_string; + +typedef struct +{ + prop_type type; + allocatable_string str; +} +prop_as_str_or_varg; + #define NESTING_ITERATIONAL 1 #define NESTING_SWITCH 2 #define NESTING_FUNCTION 3 @@ -174,6 +197,18 @@ enum }; STATIC_STACK (rewritable_break, uint8_t, uint16_t) +enum +{ + strings_global_size +}; +STATIC_STACK (strings, uint8_t, allocatable_string) + +enum +{ + props_global_size +}; +STATIC_STACK (props, uint8_t, prop_as_str_or_varg) + #ifndef JERRY_NDEBUG #define STACK_CHECK_USAGE_LHS() \ JERRY_ASSERT (IDX.current == IDX_current + 1); @@ -684,6 +719,84 @@ name_to_native_call_id (idx_t obj) JERRY_UNREACHABLE (); } +static void +free_allocatable_string (prop_as_str_or_varg p) +{ + if (p.str.was_num) + { + mem_heap_free_block ((uint8_t *) p.str.str.str); + } +} + +static allocatable_string +create_allocatable_string_from_num_uid (idx_t uid) +{ + ecma_char_t *str = mem_heap_alloc_block (ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER * sizeof (ecma_char_t), + MEM_HEAP_ALLOC_SHORT_TERM); + ecma_number_to_zt_string (lexer_get_num_by_id (uid), str, + ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER * sizeof (ecma_char_t)); + + return (allocatable_string) + { + .was_num = true, + .str = (lp_string) + { + .length = ecma_zt_string_length (str), + .str = str + } + }; +} + +static allocatable_string +create_allocatable_string_from_literal (idx_t uid) +{ + return (allocatable_string) + { + .was_num = false, + .str = lexer_get_string_by_id (uid) + }; +} + +static allocatable_string +create_allocatable_string_from_small_int (idx_t uid) +{ + const uint8_t chars_need = 4; /* Max is 255. */ + uint8_t index = 0; + ecma_char_t *str = mem_heap_alloc_block (chars_need * sizeof (ecma_char_t), + MEM_HEAP_ALLOC_SHORT_TERM); + if (uid >= 100) + { + str[index++] = (ecma_char_t) (uid/100 + '0'); + uid %= 100; + } + if (uid >= 10) + { + str[index++] = (ecma_char_t) (uid/10 + '0'); + } + str[index++] = (ecma_char_t) (uid%10 + '0'); + str[index] = ECMA_CHAR_NULL; + + return (allocatable_string) + { + .was_num = true, + .str = (lp_string) + { + .length = index, + .str = str + } + }; +} + +static prop_as_str_or_varg +create_prop_as_str_or_varg (allocatable_string str, prop_type type) +{ + return (prop_as_str_or_varg) + { + .type = type, + .str = str + }; +} + /* property_name : Identifier | StringLiteral @@ -701,18 +814,21 @@ parse_property_name (void) { STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); + STACK_PUSH (strings, create_allocatable_string_from_literal (token_data ())); break; } case TOK_NUMBER: { STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_NUMBER, token_data ()); + STACK_PUSH (strings, create_allocatable_string_from_num_uid (token_data ())); break; } case TOK_SMALL_INT: { STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_SMALLINT, token_data ()); + STACK_PUSH (strings, create_allocatable_string_from_small_int (token_data ())); break; } default: @@ -740,6 +856,9 @@ parse_property_name_and_value (void) DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_VARG_PROP_DATA, STACK_HEAD(IDX, 2), STACK_HEAD(IDX, 1)); + STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_DATA)); + STACK_DROP (strings, 1); + STACK_DROP (IDX, 2); STACK_CHECK_USAGE (IDX); } @@ -793,6 +912,7 @@ parse_property_assignment (void) STACK_DECLARE_USAGE (U16) STACK_DECLARE_USAGE (toks) STACK_DECLARE_USAGE (U8) + STACK_DECLARE_USAGE (strings) if (!token_is (TOK_NAME)) { @@ -814,6 +934,8 @@ parse_property_assignment (void) STACK_DROP (toks, 1); // name, lhs parse_property_name (); // push name + STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_GET)); + STACK_DROP (strings, 1); skip_newlines (); parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs @@ -859,6 +981,8 @@ parse_property_assignment (void) STACK_DROP (toks, 1); // name, lhs parse_property_name (); // push name + STACK_PUSH (props, create_prop_as_str_or_varg (STACK_TOP (strings), PROP_SET)); + STACK_DROP (strings, 1); skip_newlines (); parse_argument_list (AL_FUNC_EXPR, next_temp_name ()); // push lhs @@ -895,6 +1019,7 @@ simple_prop: parse_property_name_and_value (); cleanup: + STACK_CHECK_USAGE (strings); STACK_CHECK_USAGE (U8); STACK_CHECK_USAGE (toks); STACK_CHECK_USAGE (U16); @@ -925,109 +1050,86 @@ check_for_eval_and_arguments_in_strict_mode (idx_t id) } } -static bool -find_assignment_to (opcode_counter_t from, idx_t tmp_id, opcode_t *res) +/* 13.1, 15.3.2 */ +static void +check_for_syntax_errors_in_formal_param_list (uint8_t from) { - JERRY_ASSERT (res != NULL); - JERRY_ASSERT (tmp_id >= lexer_get_reserved_ids_count ()); - for (opcode_counter_t oc = from; oc > 0; oc = (opcode_counter_t) (oc - 1)) + if (STACK_SIZE (props) - from < 2 || !parser_strict_mode ()) { - *res = deserialize_opcode (oc); - if (OPCODE_IS ((*res), assignment)) + return; + } + for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1)) + { + JERRY_ASSERT (STACK_ELEMENT (props, i).type == VARG); + for (uint8_t j = from; j < i; j = (uint8_t) (j + 1)) { - if (res->data.assignment.var_left == tmp_id) + if (lp_string_equal (STACK_ELEMENT (props, i).str.str, STACK_ELEMENT (props, j).str.str)) { - return true; + EMIT_ERROR_VARG ("Duplication of literal '%s' in FormalParameterList is not allowed in strict mode", + STACK_ELEMENT (props, j).str.str.str); } } } - return false; } +/* 11.1.5 */ static void -check_for_duplication_of_param (opcode_counter_t from, uint8_t metas_num) +check_for_syntax_errors_in_obj_decl (uint8_t from) { - if (!parser_strict_mode () || metas_num < 2) + if (STACK_SIZE (props) - from < 2) { return; } - STACK_DECLARE_USAGE (IDX); - STACK_DECLARE_USAGE (U8); - STACK_DECLARE_USAGE (ops); - - STACK_PUSH (U8, 0); // seen metas - STACK_PUSH (U8, STACK_SIZE (IDX)); - - for (opcode_counter_t oc = from; oc < OPCODE_COUNTER (); oc = (opcode_counter_t) (oc + 1)) + for (uint8_t i = (uint8_t) (from + 1); i < STACK_SIZE (props); i = (uint8_t) (i + 1)) { - STACK_PUSH (ops, deserialize_opcode (oc)); - if (OPCODE_IS (STACK_TOP (ops), meta)) + JERRY_ASSERT (STACK_ELEMENT (props, i).type == PROP_DATA + || STACK_ELEMENT (props, i).type == PROP_GET + || STACK_ELEMENT (props, i).type == PROP_SET); + for (uint8_t j = from; j < i; j = (uint8_t) (j + 1)) { - switch (STACK_TOP (ops).data.meta.type) + /*4*/ + const lp_string previous = STACK_ELEMENT (props, j).str.str; + const prop_type prop_type_previous = STACK_ELEMENT (props, j).type; + const lp_string prop_id_desc = STACK_ELEMENT (props, i).str.str; + const prop_type prop_type_prop_id_desc = STACK_ELEMENT (props, i).type; + if (lp_string_equal (previous, prop_id_desc)) { - case OPCODE_META_TYPE_VARG: + /*a*/ + if (parser_strict_mode () && prop_type_previous == PROP_DATA && prop_type_prop_id_desc == PROP_DATA) { - for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (IDX); i = (uint8_t) (i + 1)) - { - if (STACK_ELEMENT (IDX, i) == STACK_TOP (ops).data.meta.data_1) - { - JERRY_ASSERT (STACK_ELEMENT (IDX, i) < lexer_get_strings_count ()); - EMIT_ERROR ("Duplication of identifier as parameter is not allowed in strict mode."); - } - } - STACK_PUSH (IDX, STACK_TOP (ops).data.meta.data_1); - STACK_INCR_HEAD (U8, 2); - break; + EMIT_ERROR_VARG ("Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode", + previous.str); } - case OPCODE_META_TYPE_VARG_PROP_DATA: + /*b*/ + if (prop_type_previous == PROP_DATA + && (prop_type_prop_id_desc == PROP_SET || prop_type_prop_id_desc == PROP_GET)) { - opcode_t res; - if (find_assignment_to (oc, STACK_TOP (ops).data.meta.data_1, &res)) - { - for (uint8_t i = STACK_TOP (U8); i < STACK_SIZE (IDX); i = (uint8_t) (i + 1)) - { - if (STACK_ELEMENT (IDX, i) == res.data.assignment.value_right) - { - JERRY_ASSERT (STACK_ELEMENT (IDX, i) < lexer_get_strings_count ()); - EMIT_ERROR ("Duplication of identifier as parameter is not allowed in strict mode."); - } - } - STACK_PUSH (IDX, res.data.assignment.value_right); - } - /* FALLTHRU. */ + EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", + previous.str); } - case OPCODE_META_TYPE_THIS_ARG: - case OPCODE_META_TYPE_VARG_PROP_GETTER: - case OPCODE_META_TYPE_VARG_PROP_SETTER: + /*c*/ + if (prop_type_prop_id_desc == PROP_DATA + && (prop_type_previous == PROP_SET || prop_type_previous == PROP_GET)) { - STACK_INCR_HEAD (U8, 2); - break; + EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be both data and accessor", + previous.str); } - default: + /*d*/ + if ((prop_type_previous == PROP_SET && prop_type_prop_id_desc == PROP_SET) + || (prop_type_previous == PROP_GET && prop_type_prop_id_desc == PROP_GET)) { - break; + EMIT_ERROR_VARG ("Parameter name '%s' in ObjectDeclaration may not be accessor of same type", + previous.str); } } } - STACK_DROP (ops, 1); - if (STACK_HEAD (U8, 2) == metas_num) - { - break; - } } - - STACK_DROP (IDX, STACK_SIZE (IDX) - STACK_TOP (U8)); - STACK_DROP (U8, 2); - - STACK_CHECK_USAGE (ops); - STACK_CHECK_USAGE (U8); - STACK_CHECK_USAGE (IDX); } /** Parse list of identifiers, assigment expressions or properties, splitted by comma. For each ALT dumps appropriate bytecode. Uses OBJ during dump if neccesary. - Returns temp var if expression has lhs, or 0 otherwise. */ + Returns number of arguments. */ static uint8_t parse_argument_list (argument_list_type alt, idx_t obj) { @@ -1038,38 +1140,35 @@ parse_argument_list (argument_list_type alt, idx_t obj) STACK_DECLARE_USAGE (U16) STACK_DECLARE_USAGE (IDX) STACK_DECLARE_USAGE (temp_names) - uint8_t args_num = 0; + STACK_DECLARE_USAGE (props) + + STACK_PUSH (U8, STACK_SIZE (props)); + STACK_PUSH (U8, TOK_OPEN_PAREN); + STACK_PUSH (U8, TOK_CLOSE_PAREN); + STACK_PUSH (U8, 0); STACK_PUSH (U16, OPCODE_COUNTER ()); switch (alt) { case AL_FUNC_DECL: { - STACK_PUSH (U8, TOK_OPEN_PAREN); // Openning token; - STACK_PUSH (U8, TOK_CLOSE_PAREN); // Ending token; DUMP_OPCODE_2 (func_decl_n, obj, INVALID_VALUE); break; } case AL_FUNC_EXPR: { - STACK_PUSH (U8, TOK_OPEN_PAREN); - STACK_PUSH (U8, TOK_CLOSE_PAREN); STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (func_expr_n, ID(1), obj, INVALID_VALUE); break; } case AL_CONSTRUCT_EXPR: { - STACK_PUSH (U8, TOK_OPEN_PAREN); - STACK_PUSH (U8, TOK_CLOSE_PAREN); STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (construct_n, ID(1), obj, INVALID_VALUE); break; } case AL_CALL_EXPR: { - STACK_PUSH (U8, TOK_OPEN_PAREN); - STACK_PUSH (U8, TOK_CLOSE_PAREN); if (is_intrinsic (obj)) { break; @@ -1089,16 +1188,16 @@ parse_argument_list (argument_list_type alt, idx_t obj) } case AL_ARRAY_DECL: { - STACK_PUSH (U8, TOK_OPEN_SQUARE); - STACK_PUSH (U8, TOK_CLOSE_SQUARE); + STACK_SET_HEAD (U8, 3, TOK_OPEN_SQUARE); + STACK_SET_HEAD (U8, 2, TOK_CLOSE_SQUARE); STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_2 (array_decl, ID(1), INVALID_VALUE); break; } case AL_OBJ_DECL: { - STACK_PUSH (U8, TOK_OPEN_BRACE); - STACK_PUSH (U8, TOK_CLOSE_BRACE); + STACK_SET_HEAD (U8, 3, TOK_OPEN_BRACE); + STACK_SET_HEAD (U8, 2, TOK_CLOSE_BRACE); STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_2 (obj_decl, ID(1), INVALID_VALUE); break; @@ -1109,8 +1208,6 @@ parse_argument_list (argument_list_type alt, idx_t obj) } } - STACK_PUSH (U8, 0); - current_token_must_be (STACK_HEAD (U8, 3)); switch (alt) @@ -1140,6 +1237,9 @@ parse_argument_list (argument_list_type alt, idx_t obj) { current_token_must_be (TOK_NAME); STACK_PUSH (IDX, token_data ()); + STACK_PUSH (props, + create_prop_as_str_or_varg (create_allocatable_string_from_literal (token_data ()), + VARG)); check_for_eval_and_arguments_in_strict_mode (STACK_TOP (IDX)); break; } @@ -1206,13 +1306,13 @@ next: { case AL_FUNC_DECL: { - check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8)); + check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4)); REWRITE_OPCODE_2 (STACK_TOP (U16), func_decl_n, obj, STACK_TOP (U8)); break; } case AL_FUNC_EXPR: { - check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8)); + check_for_syntax_errors_in_formal_param_list (STACK_HEAD (U8, 4)); REWRITE_OPCODE_3 (STACK_TOP (U16), func_expr_n, ID(1), obj, STACK_TOP (U8)); break; } @@ -1246,7 +1346,7 @@ next: } case AL_OBJ_DECL: { - check_for_duplication_of_param (STACK_TOP (U16), STACK_TOP (U8)); + check_for_syntax_errors_in_obj_decl (STACK_HEAD (U8, 4)); REWRITE_OPCODE_2 (STACK_TOP (U16), obj_decl, ID(1), STACK_TOP (U8)); break; } @@ -1256,11 +1356,15 @@ next: } } - args_num = STACK_TOP (U8); + const uint8_t args_num = STACK_TOP (U8); - STACK_DROP (U8, 3); + STACK_ITERATE (props, free_allocatable_string, STACK_HEAD (U8, 4)); + + STACK_DROP (props, (uint8_t) (STACK_SIZE (props) - STACK_HEAD (U8, 4))); + STACK_DROP (U8, 4); STACK_DROP (U16, 1); + STACK_CHECK_USAGE (props); STACK_CHECK_USAGE (U8); STACK_CHECK_USAGE (U16); STACK_CHECK_USAGE (temp_names); @@ -4006,6 +4110,8 @@ parser_init (const char *source, size_t source_size, bool show_opcodes) STACK_INIT (rewritable_break); STACK_INIT (locs); STACK_INIT (scopes); + STACK_INIT (props); + STACK_INIT (strings); HASH_INIT (intrinsics, 1); @@ -4066,6 +4172,8 @@ parser_free (void) STACK_FREE (rewritable_break); STACK_FREE (locs); STACK_FREE (scopes); + STACK_FREE (props); + STACK_FREE (strings); HASH_FREE (intrinsics); diff --git a/tests/jerry/fail/255/object_get_data.js b/tests/jerry/fail/255/object_get_data.js new file mode 100644 index 000000000..5a2184af0 --- /dev/null +++ b/tests/jerry/fail/255/object_get_data.js @@ -0,0 +1,15 @@ +// Copyright 2014 Samsung Electronics Co., Ltd. +// +// 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. + +var a = {a:1, get a() {return 1}} diff --git a/tests/jerry/fail/255/object_get_get.js b/tests/jerry/fail/255/object_get_get.js new file mode 100644 index 000000000..fb429f78c --- /dev/null +++ b/tests/jerry/fail/255/object_get_get.js @@ -0,0 +1,15 @@ +// Copyright 2014 Samsung Electronics Co., Ltd. +// +// 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. + +var a = {get a() {return undefined}, get a() {return undefined}} diff --git a/tests/jerry/object_literal-2.js b/tests/jerry/object_literal-2.js new file mode 100644 index 000000000..b99824a64 --- /dev/null +++ b/tests/jerry/object_literal-2.js @@ -0,0 +1,17 @@ +// Copyright 2014 Samsung Electronics Co., Ltd. +// +// 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. + +var a = {get a(){return undefined}, set a(b){}} + +// var b = {if:0, else:1, try:2, catch:3, finally:4}