Skip to content

Commit d650390

Browse files
authored
Fix redeclaration related eval corner cases (#4886)
- Fix cases where a function parameter binding is redeclared inside a parameter initializer eval - Fix cases where a let- or function arguments binding is redeclared inside a function block because there is a declaration in a function parameter initializer eval - Also remove the ECMA_PARSE_CHAIN_INDEX_SHIFT macro, added a debugger_eval_chain_index named field to the jerry context instead JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi [email protected]
1 parent 768a209 commit d650390

File tree

8 files changed

+158
-191
lines changed

8 files changed

+158
-191
lines changed

jerry-core/debugger/debugger.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,8 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
540540

541541
uint32_t chain_index;
542542
memcpy (&chain_index, eval_string_p, sizeof (uint32_t));
543-
uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL | (chain_index << ECMA_PARSE_CHAIN_INDEX_SHIFT);
543+
uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL;
544+
JERRY_CONTEXT (debugger_eval_chain_index) = (uint16_t) chain_index;
544545

545546
parser_source_char_t source_char;
546547
source_char.source_p = eval_string_p + 5;

jerry-core/ecma/base/ecma-globals.h

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,8 @@ typedef enum
8686
ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */
8787
} ecma_type_t;
8888

89-
#if JERRY_DEBUGGER
90-
/**
91-
* Shift for scope chain index part in ecma_parse_opts
92-
*/
93-
#define ECMA_PARSE_CHAIN_INDEX_SHIFT 16
94-
#endif /* JERRY_DEBUGGER */
95-
9689
/**
9790
* Option flags for parser_parse_script and internal flags for global_status_flags in parser context.
98-
* Note:
99-
* the last 16 bits is reserved for internal parser flags, because the debugger uses these
100-
* 16 bits to encode the scope chain skip index as well (see ECMA_PARSE_CHAIN_INDEX_SHIFT)
10191
*/
10292
typedef enum
10393
{
@@ -112,30 +102,31 @@ typedef enum
112102
* See PARSER_SAVE_STATUS_FLAGS / PARSER_RESTORE_STATUS_FLAGS. */
113103
ECMA_PARSE_ALLOW_SUPER = (1u << 5), /**< allow super property access */
114104
ECMA_PARSE_ALLOW_SUPER_CALL = (1u << 6), /**< allow super constructor call */
115-
ECMA_PARSE_INSIDE_CLASS_FIELD = (1u << 7), /**< a class field is being parsed */
116-
ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 8), /**< allow new.target access */
117-
ECMA_PARSE_FUNCTION_CONTEXT = (1u << 9), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */
105+
ECMA_PARSE_FUNCTION_IS_PARSING_ARGS = (1u << 7), /**< set when parsing function arguments */
106+
ECMA_PARSE_INSIDE_CLASS_FIELD = (1u << 8), /**< a class field is being parsed */
107+
ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 9), /**< allow new.target access */
108+
ECMA_PARSE_FUNCTION_CONTEXT = (1u << 10), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */
118109

119-
ECMA_PARSE_HAS_SOURCE_VALUE = (1u << 10), /**< source_p points to a value list
110+
ECMA_PARSE_HAS_SOURCE_VALUE = (1u << 11), /**< source_p points to a value list
120111
* and the first value is the source code */
121-
ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE = (1u << 11), /**< source_p points to a value list
112+
ECMA_PARSE_HAS_ARGUMENT_LIST_VALUE = (1u << 12), /**< source_p points to a value list
122113
* and the second value is the argument list */
123114
#if JERRY_ESNEXT
124-
ECMA_PARSE_GENERATOR_FUNCTION = (1u << 12), /**< generator function is parsed */
125-
ECMA_PARSE_ASYNC_FUNCTION = (1u << 13), /**< async function is parsed */
115+
ECMA_PARSE_GENERATOR_FUNCTION = (1u << 13), /**< generator function is parsed */
116+
ECMA_PARSE_ASYNC_FUNCTION = (1u << 14), /**< async function is parsed */
126117
#endif /* JERRY_ESNEXT */
127118

128119
/* These flags are internally used by the parser. */
129-
ECMA_PARSE_INTERNAL_FREE_SOURCE = (1u << 14), /**< free source_p data */
130-
ECMA_PARSE_INTERNAL_FREE_ARG_LIST = (1u << 15), /**< free arg_list_p data */
120+
ECMA_PARSE_INTERNAL_FREE_SOURCE = (1u << 15), /**< free source_p data */
121+
ECMA_PARSE_INTERNAL_FREE_ARG_LIST = (1u << 16), /**< free arg_list_p data */
131122
#if JERRY_ESNEXT
132-
ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 16), /**< the parser is in pre-scanning mode */
123+
ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 17), /**< the parser is in pre-scanning mode */
133124
#endif /* JERRY_ESNEXT */
134125
#if JERRY_MODULE_SYSTEM
135-
ECMA_PARSE_INTERNAL_HAS_IMPORT_META = (1u << 17), /**< module has import.meta expression */
126+
ECMA_PARSE_INTERNAL_HAS_IMPORT_META = (1u << 18), /**< module has import.meta expression */
136127
#endif /* JERRY_MODULE_SYSTEM */
137128
#if JERRY_FUNCTION_TO_STRING
138-
ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER = (1u << 18), /**< source has 4 byte marker */
129+
ECMA_PARSE_INTERNAL_HAS_4_BYTE_MARKER = (1u << 19), /**< source has 4 byte marker */
139130
#endif /* JERRY_FUNCTION_TO_STRING */
140131
#ifndef JERRY_NDEBUG
141132
/**

jerry-core/jcontext/jcontext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ struct jerry_context_t
236236
jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */
237237
uint32_t debugger_flags; /**< debugger flags */
238238
uint16_t debugger_received_length; /**< length of currently received bytes */
239+
uint16_t debugger_eval_chain_index; /**< eval chain index */
239240
uint8_t debugger_message_delay; /**< call receive message when reaches zero */
240241
uint8_t debugger_max_send_size; /**< maximum amount of data that can be sent */
241242
uint8_t debugger_max_receive_size; /**< maximum amount of data that can be received */

jerry-core/parser/js/js-parser-internal.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ typedef enum
6464
PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */
6565
PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */
6666
PARSER_DISALLOW_AWAIT_YIELD = (1u << 16), /**< throw SyntaxError for await / yield keywords */
67-
PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 17), /**< set when parsing function arguments */
68-
PARSER_FUNCTION_HAS_COMPLEX_ARGUMENT = (1u << 18), /**< function has complex (ES2015+) argument definition */
69-
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
70-
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed
67+
PARSER_FUNCTION_HAS_COMPLEX_ARGUMENT = (1u << 17), /**< function has complex (ES2015+) argument definition */
68+
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 18), /**< function has rest parameter */
69+
PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed
7170
* Note: PARSER_ALLOW_SUPER must be present */
72-
/* These four status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
73-
PARSER_ALLOW_SUPER = (1u << 21), /**< allow super property access */
74-
PARSER_ALLOW_SUPER_CALL = (1u << 22), /**< allow super constructor call
71+
/* These five status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
72+
PARSER_ALLOW_SUPER = (1u << 20), /**< allow super property access */
73+
PARSER_ALLOW_SUPER_CALL = (1u << 21), /**< allow super constructor call
7574
* Note: PARSER_CLASS_CONSTRUCTOR must be present */
75+
PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 22), /**< set when parsing function arguments */
7676
PARSER_INSIDE_CLASS_FIELD = (1u << 23), /**< a class field is being parsed */
7777
PARSER_ALLOW_NEW_TARGET = (1u << 24), /**< allow new.target parsing in the current context */
7878
PARSER_IS_METHOD = (1u << 25), /**< method is parsed */

jerry-core/parser/js/js-scanner-util.c

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,107 @@ scanner_seek (parser_context_t *context_p) /**< context */
400400
context_p->next_scanner_info_p = prev_p->next_p;
401401
} /* scanner_seek */
402402

403+
/**
404+
* Checks whether a literal is equal to "arguments".
405+
*/
406+
static inline bool JERRY_ATTR_ALWAYS_INLINE
407+
scanner_literal_is_arguments (lexer_lit_location_t *literal_p) /**< literal */
408+
{
409+
return lexer_compare_identifier_to_string (literal_p, (const uint8_t *) "arguments", 9);
410+
} /* scanner_literal_is_arguments */
411+
403412
#if JERRY_ESNEXT
404413

414+
/**
415+
* Find if there is a duplicated argument in the given context
416+
*
417+
* @return true - if there are duplicates, false - otherwise
418+
*/
419+
static bool
420+
scanner_find_duplicated_arg (parser_context_t *context_p, lexer_lit_location_t *lit_loc_p)
421+
{
422+
if (!(context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS))
423+
{
424+
return false;
425+
}
426+
427+
if (scanner_literal_is_arguments (lit_loc_p))
428+
{
429+
return true;
430+
}
431+
432+
uint16_t register_end, encoding_limit, encoding_delta;
433+
ecma_value_t *literal_p;
434+
ecma_value_t *literal_start_p;
435+
436+
const ecma_compiled_code_t *bytecode_header_p = JERRY_CONTEXT (vm_top_context_p)->shared_p->bytecode_header_p;
437+
438+
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
439+
{
440+
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
441+
442+
register_end = args_p->register_end;
443+
444+
literal_p = (ecma_value_t *) (args_p + 1);
445+
literal_p -= register_end;
446+
literal_start_p = literal_p;
447+
literal_p += args_p->literal_end;
448+
}
449+
else
450+
{
451+
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
452+
453+
register_end = args_p->register_end;
454+
455+
literal_p = (ecma_value_t *) (args_p + 1);
456+
literal_p -= register_end;
457+
literal_start_p = literal_p;
458+
literal_p += args_p->literal_end;
459+
}
460+
461+
if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING))
462+
{
463+
encoding_limit = CBC_SMALL_LITERAL_ENCODING_LIMIT;
464+
encoding_delta = CBC_SMALL_LITERAL_ENCODING_DELTA;
465+
}
466+
else
467+
{
468+
encoding_limit = CBC_FULL_LITERAL_ENCODING_LIMIT;
469+
encoding_delta = CBC_FULL_LITERAL_ENCODING_DELTA;
470+
}
471+
472+
uint8_t *byte_code_p = (uint8_t *) literal_p;
473+
474+
bool found_duplicate = false;
475+
476+
while (*byte_code_p == CBC_CREATE_LOCAL)
477+
{
478+
byte_code_p++;
479+
uint16_t literal_index = *byte_code_p++;
480+
481+
if (literal_index >= encoding_limit)
482+
{
483+
literal_index = (uint16_t) (((literal_index << 8) | *byte_code_p++) - encoding_delta);
484+
}
485+
486+
ecma_string_t *arg_string = ecma_get_string_from_value (literal_start_p[literal_index]);
487+
uint8_t *destination_p = (uint8_t *) parser_malloc (context_p, lit_loc_p->length);
488+
lexer_convert_ident_to_cesu8 (destination_p, lit_loc_p->char_p, lit_loc_p->length);
489+
ecma_string_t *search_key_p = ecma_new_ecma_string_from_utf8 (destination_p, lit_loc_p->length);
490+
scanner_free (destination_p, lit_loc_p->length);
491+
492+
found_duplicate = ecma_compare_ecma_strings (arg_string, search_key_p);
493+
ecma_deref_ecma_string (search_key_p);
494+
495+
if (found_duplicate)
496+
{
497+
break;
498+
}
499+
}
500+
501+
return found_duplicate;
502+
} /* scanner_find_duplicated_arg */
503+
405504
/**
406505
* Find any let/const declaration of a given literal.
407506
*
@@ -466,7 +565,8 @@ scanner_scope_find_lexical_declaration (parser_context_t *context_p, /**< contex
466565
{
467566
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
468567

469-
if (property_p != NULL && ecma_is_property_enumerable (*property_p))
568+
if (property_p != NULL
569+
&& (ecma_is_property_enumerable (*property_p) || scanner_find_duplicated_arg (context_p, literal_p)))
470570
{
471571
ecma_deref_ecma_string (name_p);
472572
return true;
@@ -549,15 +649,6 @@ scanner_push_literal_pool (parser_context_t *context_p, /**< context */
549649

550650
JERRY_STATIC_ASSERT (PARSER_MAXIMUM_IDENT_LENGTH <= UINT8_MAX, maximum_ident_length_must_fit_in_a_byte);
551651

552-
/**
553-
* Checks whether a literal is equal to "arguments".
554-
*/
555-
static inline bool JERRY_ATTR_ALWAYS_INLINE
556-
scanner_literal_is_arguments (lexer_lit_location_t *literal_p) /**< literal */
557-
{
558-
return lexer_compare_identifier_to_string (literal_p, (const uint8_t *) "arguments", 9);
559-
} /* scanner_literal_is_arguments */
560-
561652
/**
562653
* Current status of arguments.
563654
*/

jerry-core/vm/vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
315315
lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
316316

317317
#if JERRY_DEBUGGER
318-
uint32_t chain_index = parse_opts >> ECMA_PARSE_CHAIN_INDEX_SHIFT;
319-
parse_opts &= (1 << ECMA_PARSE_CHAIN_INDEX_SHIFT) - 1;
318+
uint32_t chain_index = JERRY_CONTEXT (debugger_eval_chain_index);
319+
JERRY_CONTEXT (debugger_eval_chain_index) = 0;
320320

321321
while (chain_index != 0)
322322
{

tests/jerry/es.next/arguments.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,37 @@ function f22 (arguments, [a = arguments]) {
218218
}
219219
f22(3.1, []);
220220

221-
function f23(arguments, eval = () => eval()) {
221+
try {
222+
function f23(p = eval("var arguments"), arguments)
223+
{
224+
}
225+
f23()
226+
assert(false)
227+
} catch (e) {
228+
assert(e instanceof SyntaxError)
229+
}
230+
231+
try {
232+
function f24(p = eval("var arguments")) {
233+
let arguments;
234+
}
235+
f24()
236+
assert(false)
237+
} catch (e) {
238+
assert(e instanceof SyntaxError)
239+
}
240+
241+
try {
242+
function f25(p = eval("var arguments")) {
243+
function arguments() { }
244+
}
245+
f25()
246+
assert(false)
247+
} catch (e) {
248+
assert(e instanceof SyntaxError)
249+
}
250+
251+
function f26(arguments, eval = () => eval()) {
222252
assert(arguments === undefined);
223253
}
224-
f23(undefined);
254+
f26(undefined);

0 commit comments

Comments
 (0)