From f31931267a096870103170f4ebcde66ba2821c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=A1l?= Date: Mon, 2 Mar 2020 10:37:41 +0100 Subject: [PATCH] Fix argument flags when invoking native function via construct (#3590) When calling a native function via construct it should not have any flags in the argument list pointer. Fixes: #3588 JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com --- .../ecma/operations/ecma-function-object.c | 17 +-- .../es2015/regression-test-issue-3588.js | 19 ++++ tests/unit-core/test-regression-3588.c | 107 ++++++++++++++++++ 3 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 tests/jerry/es2015/regression-test-issue-3588.js create mode 100644 tests/unit-core/test-regression-3588.c diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index ba9ea55fe..fd913ca44 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -1481,13 +1481,6 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ this_arg_value = ecma_make_object_value (new_this_obj_p); } -#if ENABLED (JERRY_ES2015) - if (JERRY_LIKELY (new_this_obj_p == NULL)) - { - arguments_list_p = ecma_op_function_args_set_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_SUPER); - } -#endif /* ENABLED (JERRY_ES2015) */ - /* 8. */ ecma_value_t ret_value; @@ -1495,7 +1488,15 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ { case ECMA_OBJECT_TYPE_FUNCTION: { - arguments_list_p = ecma_op_function_args_set_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT); + uintptr_t flag = ECMA_FUNC_ARG_FLAG_CONSTRUCT; +#if ENABLED (JERRY_ES2015) + if (JERRY_LIKELY (new_this_obj_p == NULL)) + { + flag |= ECMA_FUNC_ARG_FLAG_SUPER; + } +#endif /* ENABLED (JERRY_ES2015) */ + + arguments_list_p = ecma_op_function_args_set_flag (arguments_list_p, flag); ret_value = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); break; } diff --git a/tests/jerry/es2015/regression-test-issue-3588.js b/tests/jerry/es2015/regression-test-issue-3588.js new file mode 100644 index 000000000..afa6ab9bc --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3588.js @@ -0,0 +1,19 @@ +// 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. + +// Test if the native function as constructor is correctly invoked +// when used as parent "class" + +class C extends print {} +new C () diff --git a/tests/unit-core/test-regression-3588.c b/tests/unit-core/test-regression-3588.c new file mode 100644 index 000000000..575980514 --- /dev/null +++ b/tests/unit-core/test-regression-3588.c @@ -0,0 +1,107 @@ +/* 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. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +/** + * Empty constructor + */ +static jerry_value_t +construct_handler (const jerry_value_t func_obj_val, /**< function object */ + const jerry_value_t this_val, /**< this arg */ + const jerry_value_t args_p[], /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + JERRY_UNUSED (func_obj_val); + JERRY_UNUSED (this_val); + + TEST_ASSERT (args_cnt == 1); + TEST_ASSERT (jerry_get_number_value (args_p[0]) == 1.0); + + return jerry_create_undefined (); +} /* construct_handler */ + +int +main (void) +{ + /* Test JERRY_FEATURE_SYMBOL feature as it is a must-have in ES2015 */ + if (!jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Skipping test, ES2015 support is disabled.\n"); + return 0; + } + + jerry_init (JERRY_INIT_EMPTY); + + { + jerry_value_t global_obj_val = jerry_get_global_object (); + + jerry_value_t function_val = jerry_create_external_function (construct_handler); + jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) "Demo"); + jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val); + TEST_ASSERT (!jerry_value_is_error (result_val)); + TEST_ASSERT (jerry_get_boolean_value (result_val) == true); + jerry_release_value (result_val); + jerry_release_value (function_name_val); + jerry_release_value (global_obj_val); + jerry_release_value (function_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( + "class Sub1 extends Demo { constructor () { super (1); } };" + "new Sub1 ()" + ); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t result = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_release_value (result); + jerry_release_value (parsed_code_val); + } + + { + static const jerry_char_t test_source[] = TEST_STRING_LITERAL ( + "class Sub2 extends Demo { };" + "new Sub2 (1)" + ); + + jerry_value_t parsed_code_val = jerry_parse (NULL, + 0, + test_source, + sizeof (test_source) - 1, + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_is_error (parsed_code_val)); + + jerry_value_t result = jerry_run (parsed_code_val); + TEST_ASSERT (!jerry_value_is_error (result)); + + jerry_release_value (result); + jerry_release_value (parsed_code_val); + } + + jerry_cleanup (); + return 0; +} /* main */