Fix var and function declaration in eval (#4360)

Fixes #4149

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2020-12-14 11:30:45 +01:00 committed by GitHub
parent fe29bf7390
commit 29be24f056
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 70 deletions

View File

@ -823,7 +823,6 @@ void scanner_cleanup (parser_context_t *context_p);
bool scanner_is_context_needed (parser_context_t *context_p, parser_check_context_type_t check_type);
#if ENABLED (JERRY_ESNEXT)
bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p);
bool scanner_try_scan_new_target (parser_context_t *context_p);
void scanner_check_variables (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ESNEXT) */

View File

@ -1992,7 +1992,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
context.status_flags |= PARSER_LEXICAL_BLOCK_NEEDED;
}
if ((parse_opts & ECMA_PARSE_EVAL) == 0)
if (!(parse_opts & ECMA_PARSE_EVAL))
{
scanner_check_variables (&context);
}

View File

@ -14,6 +14,7 @@
*/
#include "ecma-helpers.h"
#include "ecma-lex-env.h"
#include "jcontext.h"
#include "js-parser-internal.h"
#include "js-scanner-internal.h"
@ -385,6 +386,85 @@ scanner_seek (parser_context_t *context_p) /**< context */
context_p->next_scanner_info_p = prev_p->next_p;
} /* scanner_seek */
#if ENABLED (JERRY_ESNEXT)
/**
* Find any let/const declaration of a given literal.
*
* @return true - if the literal is found, false - otherwise
*/
static bool
scanner_scope_find_lexical_declaration (parser_context_t *context_p, /**< context */
lexer_lit_location_t *literal_p) /**< literal */
{
ecma_string_t *name_p;
uint32_t flags = context_p->global_status_flags;
if (!(flags & ECMA_PARSE_EVAL)
|| (!(flags & ECMA_PARSE_DIRECT_EVAL) && (context_p->status_flags & PARSER_IS_STRICT)))
{
return false;
}
if (JERRY_LIKELY (!literal_p->has_escape))
{
name_p = ecma_new_ecma_string_from_utf8 (literal_p->char_p, literal_p->length);
}
else
{
uint8_t *destination_p = (uint8_t *) scanner_malloc (context_p, literal_p->length);
lexer_convert_ident_to_cesu8 (destination_p, literal_p->char_p, literal_p->length);
name_p = ecma_new_ecma_string_from_utf8 (destination_p, literal_p->length);
scanner_free (destination_p, literal_p->length);
}
ecma_object_t *lex_env_p;
if (flags & ECMA_PARSE_DIRECT_EVAL)
{
lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
if (property_p != NULL && ecma_is_property_enumerable (*property_p))
{
ecma_deref_ecma_string (name_p);
return true;
}
}
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
}
else
{
lex_env_p = ecma_get_global_scope (ecma_builtin_get_global ());
}
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
if (property_p != NULL && ecma_is_property_enumerable (*property_p))
{
ecma_deref_ecma_string (name_p);
return true;
}
}
ecma_deref_ecma_string (name_p);
return false;
} /* scanner_scope_find_lexical_declaration */
#endif /* ENABLED (JERRY_ESNEXT) */
/**
* Push a new literal pool.
*
@ -694,9 +774,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION)
&& (type & SCANNER_LITERAL_IS_LOCAL_FUNC) == SCANNER_LITERAL_IS_FUNC)
{
if (prev_literal_pool_p == NULL
&& (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)
&& scanner_scope_find_let_declaration (context_p, literal_p))
if (prev_literal_pool_p == NULL && scanner_scope_find_lexical_declaration (context_p, literal_p))
{
literal_p->type = 0;
continue;
@ -1504,65 +1582,6 @@ scanner_detect_eval_call (parser_context_t *context_p, /**< context */
#if ENABLED (JERRY_ESNEXT)
/**
* Find a let/const declaration of a given literal.
*
* @return true - if the literal is found, false - otherwise
*/
bool
scanner_scope_find_let_declaration (parser_context_t *context_p, /**< context */
lexer_lit_location_t *literal_p) /**< literal */
{
ecma_string_t *name_p;
if (JERRY_LIKELY (!literal_p->has_escape))
{
name_p = ecma_new_ecma_string_from_utf8 (literal_p->char_p, literal_p->length);
}
else
{
uint8_t *destination_p = (uint8_t *) scanner_malloc (context_p, literal_p->length);
lexer_convert_ident_to_cesu8 (destination_p, literal_p->char_p, literal_p->length);
name_p = ecma_new_ecma_string_from_utf8 (destination_p, literal_p->length);
scanner_free (destination_p, literal_p->length);
}
ecma_object_t *lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
if (property_p != NULL && ecma_is_property_enumerable (*property_p))
{
ecma_deref_ecma_string (name_p);
return true;
}
}
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
if (property_p != NULL && ecma_is_property_enumerable (*property_p))
{
ecma_deref_ecma_string (name_p);
return true;
}
}
ecma_deref_ecma_string (name_p);
return false;
} /* scanner_scope_find_let_declaration */
/**
* Throws an error for invalid var statements.
*/
@ -1642,8 +1661,7 @@ scanner_detect_invalid_var (parser_context_t *context_p, /**< context */
}
}
if ((context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)
&& scanner_scope_find_let_declaration (context_p, var_literal_p))
if (scanner_scope_find_lexical_declaration (context_p, var_literal_p))
{
scanner_raise_redeclaration_error (context_p);
}
@ -2072,7 +2090,7 @@ scanner_is_context_needed (parser_context_t *context_p, /**< context */
if (JERRY_UNLIKELY (check_type == PARSER_CHECK_GLOBAL_CONTEXT)
&& (type == SCANNER_STREAM_TYPE_VAR
|| (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL))
|| (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_EVAL))
|| is_import))
{
continue;
@ -2768,8 +2786,8 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
{
#if ENABLED (JERRY_ESNEXT)
literal.char_p -= data_p[1];
if (!(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)
|| !scanner_scope_find_let_declaration (context_p, &literal))
if (!scanner_scope_find_lexical_declaration (context_p, &literal))
{
func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL;

View File

@ -0,0 +1,24 @@
// 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.
let x;
try {
(0,eval)('var x');
assert(false)
} catch (e) {
assert(e instanceof SyntaxError)
}
(0,eval)('function x() {};');

View File

@ -390,7 +390,6 @@
<test id="language/eval-code/indirect/non-definable-global-var.js"><reason></reason></test>
<test id="language/eval-code/indirect/var-env-func-init-global-new.js"><reason></reason></test>
<test id="language/eval-code/indirect/var-env-func-init-global-update-configurable.js"><reason></reason></test>
<test id="language/eval-code/indirect/var-env-global-lex-non-strict.js"><reason></reason></test>
<test id="language/eval-code/indirect/var-env-var-init-global-new.js"><reason></reason></test>
<test id="language/expressions/arrow-function/dstr/ary-init-iter-no-close.js"><reason></reason></test>
<test id="language/expressions/arrow-function/dstr/dflt-ary-init-iter-no-close.js"><reason></reason></test>